Java Collection 移除元素方法及注意事项

 更新时间:2020年01月03日 10:10:49   作者:码农小胖哥  
这篇文章主要介绍了Java Collection 移除元素方法及注意事项,通过一个简单实例给大家讲解,需要的朋友可以参考下

1. 前言

操作集合是一个 Java 编程人员几乎每天都在重复的事情。今天我们来研究一下从 Java Collection 中删除元素的方法。我构建了一个简单的集合,我们以此为例子来展开探索。

 List<String> servers = new ArrayList<>();
 servers.add("Felordcn");
 servers.add("Tomcat");
 servers.add("Jetty");
 servers.add("Undertow");
 servers.add("Resin");

2. for 循环并不一定能从集合中移除元素

让我们使用传统的 foreach 循环移除 F 开头的假服务器,但是你会发现这种操作引发了 ConcurrentModificationException 异常。

 // 错误的示范 千万不要使用
 for (String server : servers) {
 if (server.startsWith("F")) {
 servers.remove(server);
 }
 }

难道 for 循环就不能移除元素了吗?当然不是!我们如果能确定需要被移除的元素的索引还是可以的。

 // 这种方式是可行
 for (int i = 0; i < servers.size(); i++) {
 if (servers.get(i).startsWith("F")) {
 servers.remove(i);
 }
}

但是这种方式我目前只演示了 ArrayList,其它的类型并没有严格测试,留给你自己探索。

3. 迭代器 Iterator 可以删除集合中的元素

在传统方式中我们使用 Iterator 是可以保证删除元素的:

 Iterator<String> iterator = servers.iterator();

 while (iterator.hasNext()) {
  String next = iterator.next();
  if (next.startsWith("F")) {
  iterator.remove();
  }
 }

4. 遍历删除元素的缺点

  • 我们需要遍历集合的每一个元素并对它们进行断言,哪怕你删除一个元素。
  • 尽管我们可以通过迭代的方式删除特定的元素,但是操作繁琐,根据集合类型的不同有潜在的 ConcurrentModificationException 异常。
  • 根据数据结构的不同,删除元素的时间复杂度也大大不同。比如数组结构的 ArrayList 在删除元素的速度上不如链表结构的 LinkedList。

5. 新的集合元素删除操作

Java 8 提供了新的集合操作 API 和 Stream 来帮助我们解决这个问题。我在以前的文章中已经介绍了 Java 8 Stream API,如果有兴趣可以去看看。

5.1 Collection.removeIf()

新的 Collection Api removeIf(Predicate<? super E> filter) 。该 Api 提供了一种更简洁的使用 Predicate (断言)删除元素的方法,于是我们可以更加简洁的实现开始的需求:

servers.removeIf(s-> s.startsWith("F"));

同时根据测试,ArrayList 和 LinkedList 的性能接近。一般推荐使用这种方式进行操作。

5.2 Stream 实现移除元素

和上面所有移除操作不同的是,其实任何操作都不会改变 Stream 源,我们仅仅是使用 Stream Api 操作数据源的副本。遵循了 数据源 -> 中间操作 -> 归纳终止 的生命周期。我们来看看使用 Stream 如何实现我们的意图。

5.2.1 通过 filter 断言实现

我们可以使用 Stream 的 filter 断言。filter 断言会把符合断言的流元素汇集成一个新的流,然后归纳起来即可,于是我们可以这么写:

// 跟以上不同的是 该方式中的断言是取反的操作。
List<String> newServers = servers.stream().filter(s -> !s.startsWith("F")).collect(Collectors.toList());

这个优点上面已经说了不会影响原始数据,生成的是一个副本。缺点就是可能会有内存占用问题。

5.2.2 通过 Collectors.partitioningBy 归纳

这种方法虽然可以满足需要但是我感觉有点投机取巧的成份。Collectors.partitioningBy() 方法本意是做二分类的。该方法会将流中符合断言的、不符合断言的元素分别归纳到两个 key 分别为 true 和 false 的 Map 中,我们可以归类得到符合和不符合的元素集。实现如下:

Map<Boolean, List<String>> f = servers.stream().collect(Collectors.partitioningBy(s -> !s.startsWith("F")));
 
 List<String> trues = f.get(Boolean.TRUE);
 System.out.println("不以 F 开头的: " + trues);

 List<String> falses = f.get(Boolean.FALSE);
 System.out.println("以 F 开头的: " + falses);

一般该方式不推荐在此场景使用,并不符合该 Api 的设计意图。

6. 总结

今天我们研究了一些从 Collections 中删除元素的方法 及其注意事项。希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!
如果你觉得本文对你有帮助,欢迎转载,烦请注明出处,谢谢!

相关文章

  • JavaMailSender实现邮箱验证功能

    JavaMailSender实现邮箱验证功能

    本篇文章主要给大家介绍了JavaMailSender实现邮箱注册验证的功能实现原理以及其中遇到的问题,一起跟着学习探讨下吧。
    2017-12-12
  • 深入理解Java8新特性之Lambda表达式的基本语法和自定义函数式接口

    深入理解Java8新特性之Lambda表达式的基本语法和自定义函数式接口

    Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。使用 Lambda 表达式可以使代码变的更加简洁紧凑
    2021-11-11
  • 详解Java包装类及自动装箱拆箱

    详解Java包装类及自动装箱拆箱

    这篇文章主要介绍了Java包装类及自动装箱拆箱,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-03-03
  • 详解mybatis-plus配置找不到Mapper接口路径的坑

    详解mybatis-plus配置找不到Mapper接口路径的坑

    这篇文章主要介绍了详解mybatis-plus配置找不到Mapper接口路径的坑,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-10-10
  • SpringBoot使用LomBok的示例代码

    SpringBoot使用LomBok的示例代码

    这篇文章主要介绍了SpringBoot使用LomBok的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-07-07
  • Java IO与NIO高效的输入输出操作深入探究

    Java IO与NIO高效的输入输出操作深入探究

    这篇文章主要为大家介绍了Java IO与NIO高效的输入输出操作深入探究,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-10-10
  • Spark使用IDEA编写wordcount的示例演示

    Spark使用IDEA编写wordcount的示例演示

    这篇文章主要介绍了Spark使用IDEA编写wordcount的示例演示,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-07-07
  • Java建造者设计模式详解

    Java建造者设计模式详解

    这篇文章主要为大家详细介绍了Java建造者设计模式,对建造者设计模式进行分析理解,感兴趣的小伙伴们可以参考一下
    2016-02-02
  • Java图形化界面设计之容器(JFrame)详解

    Java图形化界面设计之容器(JFrame)详解

    这篇文章主要介绍了Java图形化界面设计之容器(JFrame)详解,条理清晰,依次介绍了Java基本类(JFC),AWT和Swing的区别,Swing基本框架,图形化设计步骤以及组件容器的使用等相关内容,具有一定参考价值,需要的朋友可以了解下。
    2017-11-11
  • Java调取创蓝253短信验证码的实现代码

    Java调取创蓝253短信验证码的实现代码

    这篇文章主要介绍了Java调取创蓝253短信验证码的实现代码,需要的朋友可以参考下
    2018-04-04

最新评论