【问题标题】:java.lang.IllegalStateException in iterator.remove()iterator.remove() 中的 java.lang.IllegalStateException
【发布时间】:2021-08-18 00:54:13
【问题描述】:

Rocket 类包含:canCarry(Item item)>检查此物品是否可以携带/carry 使用总重量更新重量。

U2 类是 Rocket 的子类,包含:currentweight, ma​​xWeight=18 吨 项目类别包含:要运输的名称和重量。

loadU2 方法中,我试图访问一个项目列表并将其添加到一个火箭中,直到达到该火箭的 ma​​xWeight例如,我有 216 吨的物品要携带返回 12 艘船的清单。

它在 iterator.remove() 行中引发 java.lang.IllegalStateException 错误。我不知道该怎么做,但看起来它不允许我在迭代时删除项目。

public ArrayList<Rocket> loadU2(ArrayList<Item> loadItems){
    //list of ships
    ArrayList<Rocket> U2Ships = new ArrayList<Rocket>();
    for(Iterator<Item> iterator = loadItems.iterator(); iterator.hasNext();) {      
        //create a new ship
        Rocket tempShip = new U2();
        Item tempItem = iterator.next();
        //loop over items check if it can be filled then remove the item that was filled.
        while(tempShip.currentWeight<tempShip.weightLimit) {
            if(tempShip.canCarry(tempItem)){
                tempShip.carry(tempItem);
                iterator.remove();
            }           
        }
        U2Ships.add(tempShip);
    }
    return U2Ships;
}   


Exception in thread "main" java.lang.IllegalStateException
    at java.base/java.util.ArrayList$Itr.remove(ArrayList.java:980)
    at Simulation.loadU1(Simulation.java:35)
    at Main.main(Main.java:14)

代码执行的简化示例: 假设每艘船的 ma​​xWeight = 11 吨 ArrayList loadItems = [3,5,5,8,1,2,3,5] 吨

 - Ship[1]=[3,5,1,2]
 - new list to iterate over >> [5,8,3,5]
 - Ship[2]=[5,3]
 - new list to iterate over >> [8,5]
 - Ship[3]=[8]
 - new list to iterate over >> [5]
 - Ship[4]=[5]

【问题讨论】:

  • 您有一个while 循环,您可能会多次调用iterator.remove()。这是不可能的,你只能调用一次。一旦它被“删除”,你就不能再次删除它,它已经消失了。

标签: java illegalstateexception


【解决方案1】:

使用 listIterator 代替 Iterator。

ListIterator<Book> iter = books.listIterator();
while(iter.hasNext()){
    if(iter.next().getIsbn().equals(isbn)){
        iter.remove();
    }
}

喜欢这里使用。

Remove elements from collection while iterating

【讨论】:

    【解决方案2】:

    请通过创建新的 ArrayList 来重写您的代码,而不是更改其自己的迭代器中的现有列表:

    public ArrayList<Rocket> loadU2(ArrayList<Item> loadItems){
        //list of ships
        ArrayList<Rocket> U2Ships = new ArrayList<Rocket>();
        ArrayList<Item> updatedLoadItems = new ArrayList<Item>();
        for(Iterator<Item> iterator = loadItems.iterator(); iterator.hasNext();) {      
            //create a new ship
            Rocket tempShip = new U2();
            Item tempItem = iterator.next();
            //loop over items check if it can be filled then only leave the load item that was not fully filled.
            boolean addLoadItem = true;
            while(tempShip.currentWeight<tempShip.weightLimit) {
                if(tempShip.canCarry(tempItem)){
                    tempShip.carry(tempItem);
                    addLoadItem = false;
                }         
            }
            if (addLoadItem) {
              updatedLoadItems.add(tempItem);
            };
            U2Ships.add(tempShip);
        }
        loadItems.removeAll();
        loadItems.addAll(updatedLoadItems);
        return U2Ships;
    } 
    

    这不是最好的解决方案,但要提供更好的解决方案,您需要更改public ArrayList&lt;Rocket&gt; loadU2(ArrayList&lt;Item&gt; loadItems)的签名

    您可以尝试通过重构来改进您的代码。

    提示: 现在您的 loadU2 方法试图同时做这两件事:更改 loadItems 并创建 U2Ships。这直接违反了单一责任原则。试着想象一个士兵会同时开枪和扔手榴弹!当时只有一件事。

    【讨论】:

      【解决方案3】:

      问题出在这里:

      while(tempShip.currentWeight<tempShip.weightLimit) {
          if(tempShip.canCarry(tempItem)){
              tempShip.carry(tempItem);
              iterator.remove();
          }           
      }
      

      您正在循环中调用iterator.remove()。如果条件tempShip.canCarry(tempItem) 成立两次,则调用iterator.remove() 两次,这是不允许的(第二次,该项目已被删除)。

      我不知道canCarry这个方法是怎么实现的,但是注意如果tempShip.currentWeight&lt;tempShip.weightLimit为真,而tempShip.canCarry(tempItem)为假,你的循环将永远运行。

      【讨论】:

        【解决方案4】:
        public ArrayList<Rocket> loadU2(ArrayList<Item> loadItems){
            //list of ships
            int shipNum=0;
            int itemsloaded=0;
            ArrayList<Rocket> U2Ships = new ArrayList<Rocket>();
            while(!loadItems.isEmpty()) {      
                System.out.println("number of ships created: "+shipNum++);
                //create a new ship
                Rocket tempShip = new U2();
                
                //loop over items check if it can be filled then only leave the load item that was not fully filled.
             
                while(iterator.hasNext()) {  
                    Item tempItem = iterator.next();
                    if(tempShip.canCarry(tempItem)){
                        System.out.println("number of items loaded: "+(itemsloaded++));
                        tempShip.carry(tempItem);
                        iterator.remove();                                      
                     
                   } 
                }
                
                U2Ships.add(tempShip);
            }
        
            return U2Ships;
        } 
        

        感谢大家的帮助,这应该可以解决 2 个问题:infinity 和 iterator.remove()。

        【讨论】:

        • iterator.remove() 没问题,你使用它的方式有问题。事实上,您的新解决方案现在有一个错误因为您没有使用迭代器。尝试列出两个项目,这两个项目都适合一艘船,并注意您的代码如何创建两艘船而不是一艘。原因是,loadItems.remove(i) 将更改列表尾部的索引,因此在下一次迭代中跳过一个项目。使用迭代器和Iterator.remove() 可以解决这个问题。
        猜你喜欢
        • 2014-04-17
        • 2020-10-24
        • 2019-05-29
        • 2020-05-17
        • 2012-12-21
        • 2016-09-21
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多