为什么这段代码会产生NoSuchElementException?

时间:2015-05-16 23:38:52

标签: java eclipse nosuchelementexception

我正在使用eclipse。我似乎无法理解为什么这段代码会出错。这似乎完全符合逻辑,第二个我删除了那条小线,程序运行正常。我很确定焦点应该放在第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.access$500(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.awt.EventQueue$3.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.ProtectionDomain$1.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)

4 个答案:

答案 0 :(得分:3)

每次调用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();          
    }
}

答案 1 :(得分:1)

来自方法Iterator.next()的文档:

  

返回下一个元素。如果迭代没有更多元素,则抛出NoSuchElementException

next()的单次测试后,您正在调用hasNext()方法两次。

答案 2 :(得分:0)

尽管next()似乎是“getter”,但它也会推进迭代指针。即每次调用next都会返回不同的元素。

更改代码以调用next()一次,如果需要多次引用,则将返回的对象分配给变量。

答案 3 :(得分:0)

  

这似乎完全合乎逻辑......

您可以保证程序执行的一点是,在某种程度上它是完全合乎逻辑的。它将完成代码所要做的事情......一旦你理解了代码的实际内容。 (在调试时要记住这一点。)

如果“逻辑错误”在于您理解程序代码的含义。

以下是您的代码的关键部分:

    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()

假设您在循环重复开始时位于列表的最后一个元素。这是发生的事情:

  1. hasNext()true
  2. 第一个next()调用为您提供最后一个元素。
  3. 假设if测试成功,第二个next()调用会抛出异常,因为没有“next”。
  4. 解决方案是这样的:

        while(objectIterator.hasNext())
        {
            GameObject tmp = objectIterator.next();
            if(tmp.getHealth() < 1)
            {
                if(tmp.getClass() == Enemy.class) 
                    enemyUnitCount --;
                objectIterator.remove();          
            }
        }
    

    还有一些事项需要注意:

    1. 你在下一个循环中犯了同样的错误。修复它。
    2. 事实上,这个错误还有其他后果。如果你仔细观察,你会发现,如果“游戏对象”是“不健康”,你实际上最终会从列表中的不健康的游戏对象中移除游戏对象。
    3. 您评论了另一个答案:“我从未想过下一个()会......”。阅读javadoc Luke!不要只是假设Java方法可以按照你想要的方式工作。
    4. 您的代码风格需要如此关注。根据所有主流Java风格指南:

      • ifwhile个关键字后面应该有一个空格。 if和while不是方法调用。
      • 对于这些语句,左大括号应位于上一行的末尾。您应该将它放在新行上的唯一情况是前一行是不同的语句。

            while (objectIterator.hasNext()) {
                GameObject tmp = objectIterator.next();
                if (tmp.getHealth() < 1) {
                    if (tmp.getClass() == Enemy.class) {
                        enemyUnitCount --;
                    }
                    objectIterator.remove();          
                }
            }