在这种情况下使用空挡块不好做法?

时间:2015-09-05 09:58:03

标签: java nullpointerexception try-catch

我有一个粒子模拟项目,我在过去的几个小时里一直在研究,我将发布两个类。一个是Particle类,一个是main和Canvas类。我创建一个画布,然后获取其BufferStrategy和一个Graphics来绘制它。我使用更新循环来更新每个帧的粒子,并使用渲染循环来渲染每个帧的粒子。通过调用粒子arraylist中每个粒子的自渲染和自我更新方法来完成更新和渲染。现在这是我的问题。我有一个MouseListener可以在中间点击时清除所有粒子,但这会产生NullPointException,因为粒子ArrayList在更新方法迭代时被清空。

我通过使用带有空catch的try catch简单地围绕Particle的update方法中的代码来解决这个问题,因为当异常发生时没有必要做 - 所有粒子都消失了所以完成更新无关紧要。但是,我已经读到这是不好的形式。有更好的解决方案吗?

我无法弄清楚如何使代码段变粗。 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-我还有另一个快速的次要问题。在我的Particles类中使用非私有字段是不好的做法吗?例如,我应该代替这个

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

使用静态getter和setter方法访问Particle?

中的私有静态int particleCount

2 个答案:

答案 0 :(得分:2)

  

在这种情况下使用空捕获块不良做法?

是。在几乎所有情况下,使用空catch块都是非常糟糕的做法。这意味着你试图隐藏错误的东西。你没有解决问题,只是隐藏它。如果您的程序流程要求空catch块,那么在应用它之前必须要三思而后行,根据我的说法,您的工作流程或要求一定有问题。

  

一个空的捕获,因为有   发生异常时无需做什么

没有。当您面对任何Exception时,您必须采取任何行动,Exception的含义是代码中存在某些错误。

例如,您正在捕捉NullPointerException而没有做任何事情,您只是向前迈进。请考虑以下示例,

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

flyAeroplane();//Crash!!

在多线程环境中,如果多个线程正在操作您的列表,您可能会遇到异常,您应该使用ArrayList CopyOnWriteArrayList的线程安全替代方案,除此之外,您应该使用synchronized来停止多个线程同时操纵你的逻辑。

答案 1 :(得分:1)

简短回答:是的,这非常糟糕。永远不应该抓住NPE。修复你的代码,不要忽视它的破坏。对于您的Particle.particleCount,它也很糟糕,因为您可以将其设置为与包含粒子的列表无关的任何值。因此,它可能导致(在您的情况下)Particle.particleCount与列表中的项目数之间的不一致。