为什么此代码给出 NoSuchElementException?
Why is this code giving NoSuchElementException?
我正在使用日食。我似乎无法理解为什么这段代码会出错。这似乎完全合乎逻辑,第二个我删除了那条小线,程序运行正常。我很确定焦点应该在第 98 行,这也是错误所说的。我在评论中所做的另一部分似乎无缘无故地给出了完全相同的错误......为什么它会在 objectList 中走得太远?
第 98 行看起来像这样
if(objectIterator.next().getClass() == Enemy.class) //Enemy.class.isAssignableFrom(objectIterator.next().getClass()))
package robotron;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.Timer;
import javax.swing.JPanel;
import java.awt.Dimension;
import java.awt.event.*;
import java.util.*;
public class GameArea extends JPanel implements ActionListener
{
static final long serialVersionUID = 42L;
public static final int FRAME_RATE = 60;
public static final int TIME_BETWEEN_FRAMES = 1000/FRAME_RATE;
public static final int DIFFICULTY_INCREASE = 4;
public static final int LEFT_EDGE = 0;
public static final int RIGHT_EDGE = 800;
public static final int UPPER_EDGE = 0;
public static final int BOTTOM_EDGE = 600;
public static final int PLAYER_MOVE_UP_KEY = KeyEvent.VK_W;
public static final int PLAYER_MOVE_DOWN_KEY = KeyEvent.VK_S;
public static final int PLAYER_MOVE_LEFT_KEY = KeyEvent.VK_A;
public static final int PLAYER_MOVE_RIGHT_KEY = KeyEvent.VK_D;
public static final int UP_KEY = KeyEvent.VK_UP;
public static final int DOWN_KEY = KeyEvent.VK_DOWN;
public static final int LEFT_KEY = KeyEvent.VK_LEFT;
public static final int RIGHT_KEY = KeyEvent.VK_RIGHT;
public static LinkedList<Integer> keyPressedList = new LinkedList<Integer>();
public static Iterator<Integer> keyPressedIterator;
public static LinkedList<GameObject> storeList = new LinkedList<GameObject>();
public static Iterator<GameObject> storeIterator;
public static LinkedList<GameObject> objectList = new LinkedList<GameObject>();
public static Iterator<GameObject> objectIterator;
public static int difficultyIncrements = 0;
public static int enemyUnitCount = 0;
public Timer gameTimer = new Timer(TIME_BETWEEN_FRAMES, this);
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
g.setColor(Color.BLACK);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.YELLOW);
g2.fill(Player.playerBoundingBox);
for(GameObject object : objectList)
{
g2.fill(object.getBoundingBox());
}
for(GameObject object : objectList)
{
object.draw(g);
}
}
public GameArea(){
setFocusable(true);
setPreferredSize(new Dimension(800,600));
MyKeyListener keyListener = new MyKeyListener();
addKeyListener(keyListener);
gameTimer.start();
objectList.add(new Player());
}
public void actionPerformed(ActionEvent a)
{
//System.out.println(objectList);
for(GameObject storedObject : storeList)
{
objectList.addLast(storedObject);
}
storeList.clear();
for (GameObject object : objectList)
{
object.update();
object.move();
}
objectIterator = objectList.iterator();
while(objectIterator.hasNext())
{
if(objectIterator.next().getHealth() < 1)
{
if(objectIterator.next().getClass() == Enemy.class) //Enemy.class.isAssignableFrom(objectIterator.next().getClass()))
enemyUnitCount --;
objectIterator.remove();
}
}
if(enemyUnitCount == 0 )
{
objectIterator = objectList.iterator();
while(objectIterator.hasNext())
{
if(objectIterator.next().getClass() != Player.class)
{
objectIterator.remove();
}
}
initiateNewRound();
}
repaint();
}
public void initiateNewRound()
{
difficultyIncrements += DIFFICULTY_INCREASE;
gameTimer.stop();
gameTimer.setInitialDelay(1000);
spawnUnits(5 + difficultyIncrements);
gameTimer.restart();
}
public void spawnUnits(int spawnCoefficient)
{
for(int i = 0; i < spawnCoefficient*2;i++)
{
if(Math.random() * 600 < 301)
{
GameArea.objectList.add(new Walker());
}
}
for(int i = 0; i < spawnCoefficient;i++)
{
if(Math.random() * 600 < 100)
{
GameArea.objectList.add(new DeathTrap());
}
}
if(Math.random() * 600 < 200)
{
GameArea.objectList.add(new SlowTrap());
}
}
private class MyKeyListener implements KeyListener
{
public void keyPressed(KeyEvent e)
{
//System.out.println("keyPressed() " + e.getKeyCode());
if(!keyPressedList.contains(e.getKeyCode()))
{
//System.out.println("new keyPressed() " + e.getKeyCode());
keyPressedList.add(e.getKeyCode());
}
}
public void keyReleased(KeyEvent e)
{
//System.out.println("keyReleased() " + e.getKeyCode());
keyPressedList.removeFirstOccurrence(e.getKeyCode());
}
public void keyTyped(KeyEvent e)
{
}
}
}
这是错误:
这是准确的错误:
Exception in thread "AWT-EventQueue-0" java.util.NoSuchElementException
at java.util.LinkedList$ListItr.next(Unknown Source)
at robotron.GameArea.actionPerformed(GameArea.java:98)
at javax.swing.Timer.fireActionPerformed(Unknown Source)
at javax.swing.Timer$DoPostEvent.run(Unknown Source)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access0(Unknown Source)
at java.awt.EventQueue.run(Unknown Source)
at java.awt.EventQueue.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
来自方法 Iterator.next()
的文档:
Returns the next element. Throws NoSuchElementException
if the iteration has no more elements.
您在对 hasNext()
进行一次测试后调用了两次 next()
方法。
每次调用 next()
时,您都在迭代到下一个对象。看看你的代码
while(objectIterator.hasNext())
{
if(objectIterator.next().getHealth() < 1)
// ^^^^^
{
if(objectIterator.next().getClass() == Enemy.class)
// ^^^^^
enemyUnitCount --;
objectIterator.remove();
}
}
在您的 while(objectIterator.hasNext())
循环条件中,您正在检查迭代器是否有 至少一个元素 ,但随后您在每个 next
中调用两次 if(...next()...)
语句,这意味着在 next
的第二次调用中,您正在尝试访问可能不存在的元素。
要更正您的代码,只需存储 next
的结果并在需要时使用此对象,如
while(objectIterator.hasNext())
{
GameObject gameObjec = objectIterator.next();
if(gameObjec.getHealth() < 1)
{
if(gameObjec.getClass() == Enemy.class)
enemyUnitCount --;
objectIterator.remove();
}
}
虽然next()
看起来像"getter",但它也推进了迭代指针。即每次调用 next 都会 return 一个不同的元素。
更改代码以调用 next()
一次,如果需要多次引用对象 returned 则将其分配给一个变量。
It seems completely logical ...
关于程序执行,您可以保证的一件事是,在某种程度上它是完全合乎逻辑的。它会按照代码所说的去做......一旦你理解了代码实际说的是什么。 (当你调试东西时,记住这一点是值得的。)
以防万一,"logic error" 在于您对程序代码所表达内容的理解。
这是您的代码的关键部分:
while(objectIterator.hasNext())
{
if(objectIterator.next().getHealth() < 1)
{
if(objectIterator.next().getClass() == Enemy.class)
enemyUnitCount --;
objectIterator.remove();
}
}
您肯定知道,next()
推进迭代器,hasNext()
测试您是否可以仍然 推进迭代器。 (next()
方法与简单的 "getter" 不同。它有副作用。)
如果仔细查看代码,您会发现 while
循环的每次重复都会执行以下操作之一:
hasNext()
、next()
或
hasNext()
、next()
、next()
、remove()
假设您在循环重复开始时位于列表的最后一个元素处。事情是这样的:
hasNext()
表示 true
。
- 第一次
next()
调用给你最后一个元素。
- 假设
if
测试成功,第二次 next()
调用抛出异常,因为没有 "next".
解决方案是这样的:
while(objectIterator.hasNext())
{
GameObject tmp = objectIterator.next();
if(tmp.getHealth() < 1)
{
if(tmp.getClass() == Enemy.class)
enemyUnitCount --;
objectIterator.remove();
}
}
还有一些注意事项:
- 你在下一个循环中犯了同样的错误。也在那里修复它。
- 事实上,这个错误还有其他后果。如果仔细观察,您会发现如果 "game object" 是 "unhealth",您实际上最终会从列表中删除不健康游戏对象之后的游戏对象。
- 您评论了另一个答案:"I had never thought next() was gonna ..."。阅读 javadoc 卢克!不要只是假设 Java 方法会按您希望的方式工作。
您的代码风格需要注意。根据所有主流 Java 风格指南:
if
和while
关键字后应该有一个space。 If 和 while 不是方法调用。
左大括号应该在这些语句的前一行的末尾。只有当上一行是不同的语句时,才应该将它放在新的一行。
while (objectIterator.hasNext()) {
GameObject tmp = objectIterator.next();
if (tmp.getHealth() < 1) {
if (tmp.getClass() == Enemy.class) {
enemyUnitCount --;
}
objectIterator.remove();
}
}
我正在使用日食。我似乎无法理解为什么这段代码会出错。这似乎完全合乎逻辑,第二个我删除了那条小线,程序运行正常。我很确定焦点应该在第 98 行,这也是错误所说的。我在评论中所做的另一部分似乎无缘无故地给出了完全相同的错误......为什么它会在 objectList 中走得太远? 第 98 行看起来像这样
if(objectIterator.next().getClass() == Enemy.class) //Enemy.class.isAssignableFrom(objectIterator.next().getClass()))
package robotron;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.Timer;
import javax.swing.JPanel;
import java.awt.Dimension;
import java.awt.event.*;
import java.util.*;
public class GameArea extends JPanel implements ActionListener
{
static final long serialVersionUID = 42L;
public static final int FRAME_RATE = 60;
public static final int TIME_BETWEEN_FRAMES = 1000/FRAME_RATE;
public static final int DIFFICULTY_INCREASE = 4;
public static final int LEFT_EDGE = 0;
public static final int RIGHT_EDGE = 800;
public static final int UPPER_EDGE = 0;
public static final int BOTTOM_EDGE = 600;
public static final int PLAYER_MOVE_UP_KEY = KeyEvent.VK_W;
public static final int PLAYER_MOVE_DOWN_KEY = KeyEvent.VK_S;
public static final int PLAYER_MOVE_LEFT_KEY = KeyEvent.VK_A;
public static final int PLAYER_MOVE_RIGHT_KEY = KeyEvent.VK_D;
public static final int UP_KEY = KeyEvent.VK_UP;
public static final int DOWN_KEY = KeyEvent.VK_DOWN;
public static final int LEFT_KEY = KeyEvent.VK_LEFT;
public static final int RIGHT_KEY = KeyEvent.VK_RIGHT;
public static LinkedList<Integer> keyPressedList = new LinkedList<Integer>();
public static Iterator<Integer> keyPressedIterator;
public static LinkedList<GameObject> storeList = new LinkedList<GameObject>();
public static Iterator<GameObject> storeIterator;
public static LinkedList<GameObject> objectList = new LinkedList<GameObject>();
public static Iterator<GameObject> objectIterator;
public static int difficultyIncrements = 0;
public static int enemyUnitCount = 0;
public Timer gameTimer = new Timer(TIME_BETWEEN_FRAMES, this);
public void paintComponent(Graphics g)
{
Graphics2D g2 = (Graphics2D) g;
g.setColor(Color.BLACK);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.YELLOW);
g2.fill(Player.playerBoundingBox);
for(GameObject object : objectList)
{
g2.fill(object.getBoundingBox());
}
for(GameObject object : objectList)
{
object.draw(g);
}
}
public GameArea(){
setFocusable(true);
setPreferredSize(new Dimension(800,600));
MyKeyListener keyListener = new MyKeyListener();
addKeyListener(keyListener);
gameTimer.start();
objectList.add(new Player());
}
public void actionPerformed(ActionEvent a)
{
//System.out.println(objectList);
for(GameObject storedObject : storeList)
{
objectList.addLast(storedObject);
}
storeList.clear();
for (GameObject object : objectList)
{
object.update();
object.move();
}
objectIterator = objectList.iterator();
while(objectIterator.hasNext())
{
if(objectIterator.next().getHealth() < 1)
{
if(objectIterator.next().getClass() == Enemy.class) //Enemy.class.isAssignableFrom(objectIterator.next().getClass()))
enemyUnitCount --;
objectIterator.remove();
}
}
if(enemyUnitCount == 0 )
{
objectIterator = objectList.iterator();
while(objectIterator.hasNext())
{
if(objectIterator.next().getClass() != Player.class)
{
objectIterator.remove();
}
}
initiateNewRound();
}
repaint();
}
public void initiateNewRound()
{
difficultyIncrements += DIFFICULTY_INCREASE;
gameTimer.stop();
gameTimer.setInitialDelay(1000);
spawnUnits(5 + difficultyIncrements);
gameTimer.restart();
}
public void spawnUnits(int spawnCoefficient)
{
for(int i = 0; i < spawnCoefficient*2;i++)
{
if(Math.random() * 600 < 301)
{
GameArea.objectList.add(new Walker());
}
}
for(int i = 0; i < spawnCoefficient;i++)
{
if(Math.random() * 600 < 100)
{
GameArea.objectList.add(new DeathTrap());
}
}
if(Math.random() * 600 < 200)
{
GameArea.objectList.add(new SlowTrap());
}
}
private class MyKeyListener implements KeyListener
{
public void keyPressed(KeyEvent e)
{
//System.out.println("keyPressed() " + e.getKeyCode());
if(!keyPressedList.contains(e.getKeyCode()))
{
//System.out.println("new keyPressed() " + e.getKeyCode());
keyPressedList.add(e.getKeyCode());
}
}
public void keyReleased(KeyEvent e)
{
//System.out.println("keyReleased() " + e.getKeyCode());
keyPressedList.removeFirstOccurrence(e.getKeyCode());
}
public void keyTyped(KeyEvent e)
{
}
}
}
这是错误:
这是准确的错误:
Exception in thread "AWT-EventQueue-0" java.util.NoSuchElementException
at java.util.LinkedList$ListItr.next(Unknown Source)
at robotron.GameArea.actionPerformed(GameArea.java:98)
at javax.swing.Timer.fireActionPerformed(Unknown Source)
at javax.swing.Timer$DoPostEvent.run(Unknown Source)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access0(Unknown Source)
at java.awt.EventQueue.run(Unknown Source)
at java.awt.EventQueue.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
来自方法 Iterator.next()
的文档:
Returns the next element. Throws
NoSuchElementException
if the iteration has no more elements.
您在对 hasNext()
进行一次测试后调用了两次 next()
方法。
每次调用 next()
时,您都在迭代到下一个对象。看看你的代码
while(objectIterator.hasNext())
{
if(objectIterator.next().getHealth() < 1)
// ^^^^^
{
if(objectIterator.next().getClass() == Enemy.class)
// ^^^^^
enemyUnitCount --;
objectIterator.remove();
}
}
在您的 while(objectIterator.hasNext())
循环条件中,您正在检查迭代器是否有 至少一个元素 ,但随后您在每个 next
中调用两次 if(...next()...)
语句,这意味着在 next
的第二次调用中,您正在尝试访问可能不存在的元素。
要更正您的代码,只需存储 next
的结果并在需要时使用此对象,如
while(objectIterator.hasNext())
{
GameObject gameObjec = objectIterator.next();
if(gameObjec.getHealth() < 1)
{
if(gameObjec.getClass() == Enemy.class)
enemyUnitCount --;
objectIterator.remove();
}
}
虽然next()
看起来像"getter",但它也推进了迭代指针。即每次调用 next 都会 return 一个不同的元素。
更改代码以调用 next()
一次,如果需要多次引用对象 returned 则将其分配给一个变量。
It seems completely logical ...
关于程序执行,您可以保证的一件事是,在某种程度上它是完全合乎逻辑的。它会按照代码所说的去做......一旦你理解了代码实际说的是什么。 (当你调试东西时,记住这一点是值得的。)
以防万一,"logic error" 在于您对程序代码所表达内容的理解。
这是您的代码的关键部分:
while(objectIterator.hasNext())
{
if(objectIterator.next().getHealth() < 1)
{
if(objectIterator.next().getClass() == Enemy.class)
enemyUnitCount --;
objectIterator.remove();
}
}
您肯定知道,next()
推进迭代器,hasNext()
测试您是否可以仍然 推进迭代器。 (next()
方法与简单的 "getter" 不同。它有副作用。)
如果仔细查看代码,您会发现 while
循环的每次重复都会执行以下操作之一:
hasNext()
、next()
或hasNext()
、next()
、next()
、remove()
假设您在循环重复开始时位于列表的最后一个元素处。事情是这样的:
hasNext()
表示true
。- 第一次
next()
调用给你最后一个元素。 - 假设
if
测试成功,第二次next()
调用抛出异常,因为没有 "next".
解决方案是这样的:
while(objectIterator.hasNext())
{
GameObject tmp = objectIterator.next();
if(tmp.getHealth() < 1)
{
if(tmp.getClass() == Enemy.class)
enemyUnitCount --;
objectIterator.remove();
}
}
还有一些注意事项:
- 你在下一个循环中犯了同样的错误。也在那里修复它。
- 事实上,这个错误还有其他后果。如果仔细观察,您会发现如果 "game object" 是 "unhealth",您实际上最终会从列表中删除不健康游戏对象之后的游戏对象。
- 您评论了另一个答案:"I had never thought next() was gonna ..."。阅读 javadoc 卢克!不要只是假设 Java 方法会按您希望的方式工作。
您的代码风格需要注意。根据所有主流 Java 风格指南:
if
和while
关键字后应该有一个space。 If 和 while 不是方法调用。左大括号应该在这些语句的前一行的末尾。只有当上一行是不同的语句时,才应该将它放在新的一行。
while (objectIterator.hasNext()) { GameObject tmp = objectIterator.next(); if (tmp.getHealth() < 1) { if (tmp.getClass() == Enemy.class) { enemyUnitCount --; } objectIterator.remove(); } }