【问题标题】:Cannot remove element from an Array List [closed]无法从数组列表中删除元素 [关闭]
【发布时间】:2019-02-06 14:50:18
【问题描述】:

一些背景知识:我是 Java 新手,正在学习基本的 Java 课程。我目前正在进行课程的最后一个项目,并完成了除了最后一段代码之外的所有内容。出于某种原因,我很难从数组列表中删除一个元素。这是我正在处理的代码:

public static void delete(String bookID) {
    for (book eachElement : catalog) {
        if (eachElement.getBookID().equals(bookID)) {
            catalog.remove(eachElement);
            return;
        }
    }
}

代码执行,没有运行时错误,但不会删除任何内容。 另外,我知道在 remove 语句之前一切正常,因为我有另一种方法可以使用与 select bookID 字符串相同的 for 和 if 语句来计算计算。

【问题讨论】:

  • 它不会删除任何东西 - 可能是因为没有带有 arg bookId 的元素?
  • 您应该检查您的 bookID 是否真的等于列表中的 ID 之一,包括大小写等。为此使用调试器。但是一旦你这样做了 - 你会得到一个并发更新异常,因为你应该只能在迭代它时从列表中删除,如果你使用列表的迭代器(显式)。
  • 检查this
  • @RealSkeptic 他应该没问题,因为在删除它之后returns(虽然这不是好的做法)。
  • 由于这是一个静态方法,这意味着您的catalog 也是静态的,您确定它没有在代码中的其他地方更新吗?

标签: java arrays arraylist


【解决方案1】:

在 forEach 循环中,您不应该也不能从集合中删除元素。

请阅读 Java 中 ArrayList 的文档。

https://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html

您实际上可以看到,ArrayList.remove(Object o) 如果 o 在列表中,则将其删除,因此不需要您的方法。

所以答案是,用你的 ID 找到 book 对象,然后将其删除。或者更好地使用地图来存储您的数据。

在你的情况下

Book b = null;
for(Book book : books) {
     if(book.getBookId().equals(bookId)) {
         b = book.getBookId();
         break;
     }
}
books.remove(b);

或者,如果您喜欢 Java8,那么您确实应该:D

books.stream().filter(b -> b.getBookId().equals(bookId)).getFirst().ifPresent(books::remove);

【讨论】:

  • @RealSkeptic 对不起我的错,修复它。顺便说一句好名字:D
  • 好。所以现在没有逻辑问题。但是您仍然需要对列表进行两次迭代,这是不必要的。
  • @RealSkeptic 我不是,删除是第二个是正确的,但是没有其他方法,除非您按索引删除,但这也不是更好。使用此数据存储类型和参数。这就是为什么我真的建议使用 Map,甚至是 Set 并使用 Book 参数而不是 String。
  • 不,您可以使用迭代器删除。请参阅 Zgurskyi 的回答。
  • 我喜欢直播回答 +1
【解决方案2】:

需要使用迭代器,否则会得到java.util.ConcurrentModificationException

public static void delete(String bookID) {
    for (Iterator<Book> it = catalog.listIterator(); it.hasNext(); ) {
        Book book = it.next();
        if (book.getBookID().equalsIgnoreCase(bookID)) {
            it.remove(book);
            return;
        }
    }
}

注意:equalsIgnoreCase 用于丢弃大小写差异。

java.util.ConcurrentModificationException 被抛出,因为您在列表上执行 2 个操作:iterationremoval。所以,实际上,还有另一种方法 - 在迭代的每个步骤中复制列表

public static void delete(String bookID) {
    for (Book book : new ArrayList<>(catalog)) {
        if (book.getBookID().equalsIgnoreCase(bookID)) {
            catalog.remove(book);
            return;
        }
    }
}

注意:出于性能考虑(每一步的二次内存使用和线性删除),我不推荐最后一种方法。我给出这个例子只是为了强调java.util.ConcurrentModificationException 被抛出的根本原因。

【讨论】:

  • 不需要对重复使用不同的逻辑。只需从第一个循环中删除return,它将删除所有重复项,而无需两次迭代列表。
  • 是的,你是对的。
【解决方案3】:

在使用迭代器时删除元素是未定义的。更好的方法是使用 removeIf。

 catalog.removeIf(eachElement -> eachElement.getBookID().equals(bookId)); 

【讨论】:

  • 很好,但是由于 OP 在删除元素后返回,如果列表包含重复项,则逻辑不同。
【解决方案4】:

您需要使用迭代器才能在使用循环时删除项目。 还要仔细检查 id 是否存在(制作一些 System.out.println("test") 并检查它是否正在进入范围)。

【讨论】:

    猜你喜欢
    • 2019-09-19
    • 1970-01-01
    • 2015-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-28
    • 1970-01-01
    相关资源
    最近更新 更多