我有一个粒子模拟项目,我已经工作了很多个小时,我将发布两个类。一个是粒子类,一个是main和Canvas类。我创建一个画布,然后得到它的BufferStrategy和一个Graphics在上面绘制。我使用更新循环来更新每一帧的粒子,并使用渲染循环来渲染每一帧的粒子。更新和渲染都是通过调用粒子数组列表中每个粒子的自渲染和自更新方法来完成的。现在这是我的问题。我有一个MouseListener,它在中键单击时清除所有粒子,但这会创建一个NullPointException,因为粒子ArrayList在更新方法迭代时被清空。
我解决这个问题的方法是简单地用一个带有空捕捉的try-catch来包围粒子更新方法中的代码,因为当异常发生时,无需执行任何操作-所有粒子都消失了,所以完成更新并不重要。然而,我读到这是一种糟糕的形式。有更好的解决方案吗?
我不知道如何使代码段加粗。try catch接近Parpse类的末尾。
粒子类别:
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;
}
}
画布类:
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粒子计数?
简短回答:是的,这太糟糕了。NPE永远不应该被抓到。修复您的代码,不要忽略它已损坏。至于你的粒子。particleCount也不好,因为可以将其设置为与包含粒子的列表无关的任何值。因此,它可能导致(在您的情况下确实如此)粒子之间的不一致性。particleCount和列表中的项数。
在这种情况下,使用空挡块是否是一种不好的做法?
是的。在几乎所有情况下使用空catch
块都是非常糟糕的做法。这意味着您试图隐藏错误的东西。您没有解决问题,只是隐藏了它。如果您的程序流需要空catch
块,那么您必须在应用它之前三思而后行,根据我的说法,您正在处理的流或需求一定有问题。
空捕获,因为发生异常时没有必要做任何事情
不。当您面对任何Exception
时,您必须采取任何行动,Exception
的含义是您的代码中出现了错误。
例如,您正在捕获NullPointerException,并且没有做任何事情,您只是在继续前进。考虑以下示例,
try {
checkAeroplane();
} catch(TechnicalProblemException e) {
//No action needed
}
flyAeroplane();//Crash!!
在多线程环境中,如果多个线程正在操作您的列表,您可能会面临异常,您应该使用ArrayList
CopyOnWriteArrayList
的线程安全替代方案,除此之外,您应该使用同步
停止多个线程同时操作您的逻辑。
问题内容: 我已阅读以下讨论: 如果私有帮助器方法可以是静态的,则它们应该是静态的;如果它们的类没有成员变量,则所有方法应该是静态的。 似乎人们通常会接受静态方法,但由于以下两个原因,对此有些怀疑: 他们很难测试。 他们违反了OO原则。(一个人说,它们是函数,而不是方法。) 最可接受的静态方法是 私有静态 方法。但是,为什么为什么根本不存在静态方法呢?在什么情况下,它们是最优先采用的方法? 问题答
问题内容: 想象这样的情况: 现在,我从理论上担心,在哪里克隆状态(中的第四条语句),可能会发生我没有获得该状态的最新版本的情况- 由于先前调用的某些调用正在等待中,这是否是正确的假设? 现在,我的问题是,如果我以以下方式(基本上与回调参数一起使用)重写上述代码,它会更安全吗?(就不处于不同步状态而言)。 我是否还需要在内部采取一些其他措施(第二个重写版本)? ps。只是更改状态的函数-假设当用户
问题内容: 因为调用flush()获取每个实体都从内存持久到数据库。因此,如果我使用过多的不必要的flush()调用,可能会花费很多时间,因此对于性能而言不是一个好的选择。这是一种我不知道何时调用flush()的情况? 我的问题是:是否可以避免调用No.1同花顺? 我担心的事情是:为了执行 item.setOrder(ord) ,我们需要ord的数据库ID。而且仅调用 em.persist(ord
这可能是一个微不足道的问题,但是阅读ARG和ENV的文档并没有让我明白。 我正在构建一个PHP-FPM容器,我希望能够根据用户需要启用/禁用一些扩展。 如果可以在Dockerfile中通过在构建命令上添加条件和传递标志来实现这一点,那就太好了,但是不支持AFAIK。 在我的情况下,我个人的方法是在容器启动时运行一个小脚本,如下所示: 这就是我的的样子: 目前这是工作,但。。。如果我想添加20个(随
我见过很多次scala代码使用Option(对于简单值)或[List[Error],T]来处理错误。 这为这样的代码提供了位置 这会产生一个不太好的代码嵌套,迫使您处理每一步的失败,并迫使您让所有函数返回一个[...] 所以我想知道 > 在scala(或一般的函数式编程)中不鼓励使用异常 使用它们有任何缺点(关于不可变性或代码并发性) 异常与原理或函数式编程有些冲突 你可以想出一个更好的方法来编写
问题内容: 我已经多次听到在HTML 中使用JavaScript事件(例如)是不正确的做法,因为它不利于语义。我想知道不利之处以及如何解决以下代码? 问题答案: 您可能正在谈论简洁的Javascript,看起来像这样: 中央javascript文件中的逻辑如下所示: 优点是 行为(JavaScript)与表示(HTML)分开 没有语言的混合 您正在使用像jQuery这样的javascript框架,