2015-09-05 233 views
0

我有一個粒子模擬項目,我一直在研究最後幾個小時,這是我將發佈的兩個類。一個是粒子類,一個是main和Canvas類。我創建一個畫布,然後獲取其BufferStrategy和一個圖形來繪製它。我使用更新循環來更新每個幀的粒子和渲染循環以每幀渲染粒子。更新和渲染都是通過調用粒子陣列列表中每個粒子的自渲染和自更新方法來完成的。這是我的問題。我有一個MouseListener,在中間點擊時清除所有粒子,但是這會創建一個NullPointException,因爲當更新方法遍歷它時,粒子ArrayList被清空。在這種情況下是否使用空的catch catch塊不良做法?

我解決了這個問題,只需將Particle的update方法中的代碼用try catch捕獲一個空捕獲來解決,因爲當發生異常時沒有必要去做 - 所有的粒子都不見了,所以完成更新不會物。不過,我已經讀過那種糟糕的形式。有更好的解決方案嗎?

我不知道如何使代碼段加粗。 try catch接近Particle類的末尾。

顆粒類:

import java.awt.Graphics; 
import java.util.ArrayList; 

public class Particle { 
    static int G = 1; //gravity constant 
    double xPos; 
    double yPos; 
    double xVel; 
    double yVel; 
    int radius; 
    static int particleCount = 0; 
    double mass; 


    public Particle(int xp, int yp 
      ,double xv,double yv, int r){ 
     xPos=xp; 
     yPos=yp; 
     xVel=xv; 
     yVel=yv; 
     radius=r; 
     mass = Math.PI*Math.pow(radius,2); 
     particleCount++; 
    } 

    void drawParticle(Graphics g){ 
     g.fillOval((int)Math.round(xPos), (int)Math.round(yPos), 2*radius, 2*radius); 
    } 
    void updateParticle(int thisParticleIndex, ArrayList<Particle> list){ 
     //update position 
     xPos+=xVel; 
     yPos+=yVel; 

     //update velocity 
     //F = G*m1*m2/r^2 
     double M; //let M = m1*m2 
     double r; 
     double Fx=0; 
     double Fy=0; 
     double dF; 
     double dFx; 
     double dFy; 
     double theta; 

     Particle p; 
     try { 
      for(int i=0; i<list.size();i++){ 
       if(i!=thisParticleIndex){ 
        p = list.get(i); 
        r = Math.sqrt(Math.pow((p.xPos+p.radius) - (xPos + radius), 2) + 
          Math.pow((p.yPos+p.radius) - (yPos + radius), 2)); 
        if(r<5) 
         continue; 
        M = mass + p.mass; 
        dF = G*M/Math.pow(r,2); 
        theta = Math.atan2((p.yPos+p.radius) - (yPos + radius), 
          (p.xPos+p.radius) - (xPos + radius)); 
        dFx = dF*Math.cos(theta); 
        dFy = dF*Math.sin(theta); 
        Fx += dFx; 
        Fy += dFy; 
       } 
      } 
     } catch (NullPointerException e) { 
      //This try catch is needed for when all particles are cleared 
     } 

     xVel += Fx/mass; 
     yVel += Fy/mass; 
    } 
} 

Canvas類:

public class MainAR extends Canvas implements Runnable { 
    private static int width = 600; 
    private static int height = 600; 

    private Thread gameThread; 
    private JFrame frame; 
    private boolean running = false; 

    private ArrayList<Particle> particles = new ArrayList<>(); 
    private int WIDTH = 800; 
    private int HEIGHT = 800; 
    private int mouseX = 0; 
    private int mouseY = 0; 
    private int radius=15; 
    private boolean drawMouse = true; 
    private boolean mouseDown = false; 
    private JLabel instructions; 

     public MainAR() { 
       setSize(width,height); 
       frame = new JFrame(); 
       frame.setTitle("Particle Simulator"); 
       frame.add(this); 
       frame.pack(); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.setVisible(true); 
       start(); 

       Particle a = new Particle((int)(0.3*WIDTH),(int)(0.3*HEIGHT),0,0,15); 
       Particle b = new Particle((int)(0.3*WIDTH),(int)(0.6*HEIGHT),0,0,20); 
       Particle c = new Particle((int)(0.6*WIDTH),(int)(0.3*HEIGHT),0,0,10); 
       Particle d = new Particle((int)(0.6*WIDTH),(int)(0.6*HEIGHT),0,0,25); 

       particles.add(a); 
       particles.add(b); 
       particles.add(c); 
       particles.add(d); 

       addMouseMotionListener(new MouseMotionListener(){ 
        public void mouseDragged(MouseEvent e) { 
         mouseX = e.getX(); 
         mouseY = e.getY(); 
         if(SwingUtilities.isLeftMouseButton(e)) 
          mouseDown = true; 
        } 

        public void mouseMoved(MouseEvent e) { 
         mouseX = e.getX(); 
         mouseY = e.getY(); 
        } 
       }); 
       addMouseWheelListener(new MouseWheelListener(){ 
        public void mouseWheelMoved(MouseWheelEvent e) { 
         radius -= e.getWheelRotation(); 
         if(radius<1) 
          radius = 1; 
        } 
       }); 
       addMouseListener(new MouseListener(){ 
        public void mouseClicked(MouseEvent e) { 
         if(SwingUtilities.isLeftMouseButton(e)) 
          particles.add(new Particle((int)(mouseX-radius),(int)(mouseY-radius),0,0,radius)); 
         if(SwingUtilities.isRightMouseButton(e)) 
          instructions.setVisible(false); 
        } 
        public void mouseEntered(MouseEvent e) { 
         drawMouse = true; 
         mouseX = e.getX(); 
         mouseY = e.getY(); 
        } 
        public void mouseExited(MouseEvent e) { 
         drawMouse = false; 
        } 
        public void mousePressed(MouseEvent e) { 
         if(SwingUtilities.isRightMouseButton(e)) 
          instructions.setVisible(false); 
         if(SwingUtilities.isMiddleMouseButton(e)){ 
          Particle.particleCount = 0; 
          particles.clear(); 
         } 

        } 
        public void mouseReleased(MouseEvent e) { 
         mouseDown = false; 
        } 
       }); 
     } 

     public synchronized void start() { 
       running = true; 
       gameThread = new Thread(this, "Display"); 
       gameThread.start(); 
     } 

     public synchronized void stop() { 
       running = false; 
       try { 
         gameThread.join(); 
       } catch (InterruptedException e) { 
         e.printStackTrace(); 
       } 
     } 

     public void run() { 
       while(running) { 
        try { 
         Thread.sleep(2); 
        } catch (InterruptedException e) { 
         // TODO Auto-generated catch block 
         e.printStackTrace(); 
        } 
         update(); 
         render(); 
       } 
     } 

     private void update() { 
      if(mouseDown) 
       particles.add(new Particle((int)(mouseX-radius),(int)(mouseY-radius),0,0,radius)); 
      for(int i=0; i<particles.size();i++) 
       particles.get(i).updateParticle(i,particles); 
      frame.setTitle("Particle Simulator" + particles.size() + "particles"); 
     } 

     private void render() { 
       BufferStrategy bs = getBufferStrategy(); 
       if (bs == null){ 
         createBufferStrategy(3); 
         return; 
       } 

       Graphics g = bs.getDrawGraphics(); 
       ((Graphics2D)g).setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON); 
       g.setColor(Color.WHITE); 
       g.fillRect(0, 0, getWidth(), getHeight()); 
       g.setColor(Color.BLACK); 
       g.fillOval((int)(mouseX-radius), (int)(mouseY-radius), 2*radius, 2*radius); 
       for(Particle p : (ArrayList<Particle>)particles.clone()) //cloning prevents Concurrent Modification Exception error 
        p.drawParticle(g); 
       g.dispose(); 
       bs.show(); 
     } 

     public static void main(String[] args){ 
     MainAR m = new MainAR(); 

     } 
} 

PS-我還有一個快速的二次問題。在我的粒子類中使用非私有字段是不好的做法嗎?例如,我應該而不是這個

if(SwingUtilities.isMiddleMouseButton(e)){ 
          Particle.particleCount = 0; 
          particles.clear(); 
         } 

已使用靜態getter和setter方法來訪問粒子內的私有靜態int particleCount嗎?

+2

你有沒有考慮過測試null?你是否考慮過捕獲NullPointerException?你有沒有考慮修復讓你進入狀態爲空的狀態的錯誤? – EJP

+0

它可以捕獲'RuntimeException'的子類,但很少,絕對不會出現'NullPointerException'。參見[this](http://stackoverflow.com/questions/6115896/java-checked-vs-unchecked-exception-explanation)問題。 – bcsb1001

+0

對於null的測試不會奏效,因爲它可能在測試完成後立即被刪除嗎?我對線程相當陌生。問題是我認爲,因爲運行線程和GUI線程同時運行,所以在更新過程中可以調用清晰的粒子行。我不知道如何解決這個問題,除了發出異常,忽略它。我的問題是這是否很糟糕 – Esoremada

回答

2

在這種情況下是否使用空的catch catch塊壞習慣?

是的。在幾乎所有情況下,使用空的catch塊都是非常糟糕的做法。這意味着你試圖隱藏錯誤的東西。你沒有解決問題,只是隱藏了它。如果你的程序流程要求有空的塊,那麼在應用它之前你必須三思而後行,並且根據我的說法,你的工作流程或需求肯定有問題。

空抓,因爲沒有什麼 必要時發生異常

號,當你面對任何Exception你必須採取任何行動,這樣做了,Exception意思是有東西在你的代碼中發生錯誤。

例如,您正在捕獲NullPointerException,並且無需執行任何操作即可繼續操作。考慮下面的例子中,

try { 
    checkAeroplane(); 
} catch(TechnicalProblemException e) { 
    //No action needed 
} 

flyAeroplane();//Crash!! 

在多線程環境中,你可能會面對異常,如果有多個線程操作的列表,你應該使用的ArrayListCopyOnWriteArrayList並分開,你應該使用synchronized線程安全的替代停止操縱你的邏輯同時通過多個線程。

+1

你簡單的解決方案是不夠的。該列表是從另一個線程修改的,因此,例如,在評估「if(particle!= null)」時,粒子可能是非空的,但在之後變爲null。 –

+2

好的,謝謝你我會學習更多關於同步的知識,然後完成這個項目 – Esoremada

1

簡短回答:是的,這是非常糟糕的。 NPE不應該被抓住。修復你的代碼,不要忽略它的破壞。至於你的Particle.particleCount,這也不好,因爲你可以將它設置爲任何獨立於包含粒子的列表的值。因此,它可能導致(並且在您的情況下)導致Particle.particleCount與列表中的項目數量之間的不一致。

相關問題