【问题标题】:How to delete an element whilst looping through the array如何在遍历数组时删除元素
【发布时间】:2019-05-01 12:56:35
【问题描述】:

我有一个包含其他对象列表的对象,其中包含另一个对象列表。很像 DTO。 在这些对象中,有另一个类型的对象列表,如果该对象包含特定的字符串,我想在其中删除该元素。

例如

CustomerDTO customerDTO = CustomerTransformer.transformCustomer(custom);
List<InfoDTO> info = customerDTO.getInfo();
info(infoDTO -> {
    List<MoreDTO> d = infoDTO.getMore();
    for (MoreDTO moreDTO : d) {
        List<ChannelDTO> channels = MoreDTO.getChannels();
        for (ChannelDTO cdto : contentChannels) {
            if ("apple".equals(cdto.getId())) {
                moreDTO.getChannels().remove(cdto);
            }
        }
    }

});

但这看起来确实效率不高,并且可能会更改空指针?有没有更好的写法?使用流和在流中使用过滤器会有帮助吗?

我是 Java 新手。

【问题讨论】:

  • 这不是关于效率,而是关于正确性。您的代码将因 ConcurrentModificationException 而失败。在做出假设之前,您确实需要测试您的代码。
  • 我猜你需要为此使用Iterator
  • 查看我的答案,如果您需要帮助,请告诉我

标签: java arrays java-8 java-stream


【解决方案1】:

在迭代/循环时不能从列表中删除元素,会有一个ConcurrentModificationException

为了避免这种情况,您可以在这里使用 Java 8 过滤器,以这种方式 -

contentChannels = contentChannels
 .stream()
 .filter(cdto->(!"apple".equals(cdto.getId())))
 .collect(Collectors.toList());

另一个选项是使用removeIf()

【讨论】:

  • 过滤和创建新列表与从列表中删除元素完全不同。
  • 同意,那样的话removeIf() 会更好
  • 我不认为过时的括号提高了可读性。此外,请注意在源代码中使用"apple" 而不是“apple”
【解决方案2】:

上面的代码不起作用请参考@JB Nizet 评论,

Triggering a ConcurrentModificationException

本质上,ConcurrentModificationException 用于在我们迭代的内容被修改时快速失败。让我们通过一个简单的测试来证明这一点:

List<Integer> integers = newArrayList(1, 2, 3);

for (Integer integer : integers) {
    integers.remove(1);
}

所以你可以使用forEachremoveIf来避免ConcurrentModificationException

List<InfoDTO> info = customerDTO.getInfo();
info.forEach(more->more.getMore().forEach(channelDto->channelDto.getChannels().removeIf(cdto->"apple".equals(cdto.getId()))));

或者如果你只有List&lt;ChannelDTO&gt;

List<ChannelDTO> channels = MoreDTO.getChannels();
channels.removeIf(cdto->"apple".equals(cdto.getId()));

【讨论】:

  • 一个简单的测试不应依赖于未指定的第 3 方库。标准 Java API 中没有 newArrayList。此外,使用List&lt;Integer&gt; 是一个不好的例子。读者很容易认为这段代码删除了元素 1,而实际上它删除了 index 1 处的元素 2。也许,您更愿意使用integers.remove(integer);,以便更接近 OP 的代码。
猜你喜欢
  • 2013-06-23
  • 2013-08-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-13
  • 1970-01-01
  • 2013-07-22
相关资源
最近更新 更多