集合操作,CollectionUtils工具类

集合操作,CollectionUtils工具类

这篇讲的是在apache下的CollectionUtils, 而不是springframework下的CollectionUtils。

首先需要引入相关jar包:

<dependency><groupId>org.apache.commons</groupId><artifactId>commons-collections4</artifactId><version>4.3</version>
</dependency>

一、API常用方法

 /*** 1、除非元素为null,否则向集合添加元素*/CollectionUtils.addIgnoreNull(personList,null);/*** 2、将两个已排序的集合a和b合并为一个已排序的列表,以便保留元素的自然顺序*/CollectionUtils.collate(Iterable<? extends O> a, Iterable<? extends O> b)/*** 3、将两个已排序的集合a和b合并到一个已排序的列表中,以便保留根据Comparator c的元素顺序。*/CollectionUtils.collate(Iterable<? extends O> a, Iterable<? extends O> b, Comparator<? super O> c)/*** 4、返回该个集合中是否含有至少有一个元素*/CollectionUtils.containsAny(Collection<?> coll1, T... coll2)/*** 5、如果参数是null,则返回不可变的空集合,否则返回参数本身。(很实用 ,最终返回List EMPTY_LIST = new EmptyList<>())*/CollectionUtils.emptyIfNull(Collection<T> collection)/*** 6、空安全检查指定的集合是否为空*/CollectionUtils.isEmpty(Collection<?> coll)/*** 7、 空安全检查指定的集合是否为空。*/CollectionUtils.isNotEmpty(Collection<?> coll)/*** 8、反转给定数组的顺序。*/CollectionUtils.reverseArray(Object[] array);/*** 9、差集*/CollectionUtils.subtract(Iterable<? extends O> a, Iterable<? extends O> b)/*** 10、并集*/CollectionUtils.union(Iterable<? extends O> a, Iterable<? extends O> b)/*** 11、交集*/CollectionUtils.intersection(Collection a, Collection b)/***12、 交集的补集(析取)*/CollectionUtils.disjunction(Collection a, Collection b)

二、非对象集合交、并、差处理
对于集合取交集、并集的处理其实有很多种方式,这里就介绍3种

第一种 是CollectionUtils工具类
第二种 是List自带方法
第三种 是JDK1.8 stream 新特性

1、CollectionUtils工具类
下面对于基本数据(包扩String)类型中的集合进行demo示例。

 public static void main(String[] args) {String[] arrayA = new String[] { "1", "2", "3", "4"};String[] arrayB = new String[] { "3", "4", "5", "6" };List<String> listA = Arrays.asList(arrayA);List<String> listB = Arrays.asList(arrayB);//1、并集 unionSystem.out.println(CollectionUtils.union(listA, listB));//输出: [1, 2, 3, 4, 5, 6]//2、交集 intersectionSystem.out.println(CollectionUtils.intersection(listA, listB));//输出:[3, 4]//3、交集的补集(析取)disjunctionSystem.out.println(CollectionUtils.disjunction(listA, listB));//输出:[1, 2, 5, 6]//4、差集(扣除)System.out.println(CollectionUtils.subtract(listA, listB));//输出:[1, 2]}

2、List自带方法

 public static void main(String[] args) {String[] arrayA = new String[] { "1", "2", "3", "4"};String[] arrayB = new String[] { "3", "4", "5", "6" };List<String> listA = Arrays.asList(arrayA);List<String> listB = Arrays.asList(arrayB);//1、交集List<String>  jiaoList = new ArrayList<>(listA);jiaoList.retainAll(listB);System.out.println(jiaoList);//输出:[3, 4]//2、差集List<String>  chaList = new ArrayList<>(listA);chaList.removeAll(listB);System.out.println(chaList);//输出:[1, 2]//3、并集 (先做差集再做添加所有)List<String>  bingList = new ArrayList<>(listA);bingList.removeAll(listB); // bingList为 [1, 2]bingList.addAll(listB);  //添加[3,4,5,6]System.out.println(bingList);//输出:[1, 2, 3, 4, 5, 6]}

注意 : intersection和retainAll的差别

它们的返回类型是不一样的,intersection返回的是一个新的List集合,而retainAll返回是Bollean类型。

那就说明retainAll方法是对原有集合进行处理再返回原有集合,会改变原有集合中的内容。

注意 : Arrays.asList将数组转集合不能进行add和remove操作。

原因:调用Arrays.asList()生产的List的add、remove方法时报异常,这是由Arrays.asList() 返回的市Arrays的内部类ArrayList, 而不是java.util.ArrayList。

所以正确做法如下

  String[] array = {"1","2","3","4","5"};List<String> list = Arrays.asList(array);List arrList = new ArrayList(list);arrList.add("6");

3、JDK1.8 stream 新特性

 public static void main(String[] args) {String[] arrayA = new String[] { "1", "2", "3", "4"};String[] arrayB = new String[] { "3", "4", "5", "6" };List<String> listA = Arrays.asList(arrayA);List<String> listB = Arrays.asList(arrayB);// 交集List<String> intersection = listA.stream().filter(item -> listB.contains(item)).collect(toList());System.out.println(intersection);//输出:[3, 4]// 差集 (list1 - list2)List<String> reduceList = listA.stream().filter(item -> !listB.contains(item)).collect(toList());System.out.println(reduceList);//输出:[1, 2]// 并集 (新建集合:1、是因为不影响原始集合。2、Arrays.asList不能add和remove操作。List<String> listAll = listA.parallelStream().collect(toList());List<String> listAll2 = listB.parallelStream().collect(toList());listAll.addAll(listAll2);System.out.println(listAll);//输出:[1, 2, 3, 4, 3, 4, 5, 6]// 去重并集 List<String> list =new ArrayList<>(listA);list.addAll(listB);List<String> listAllDistinct = list.stream().distinct().collect(toList());System.out.println(listAllDistinct);//输出:[1, 2, 3, 4, 5, 6]}

总结 :这三种我还是最喜欢第一种方式,因为第二种还需要确定该集合是否被多次调用。第三种可读性不高。

三、对象集合交、并、差处理
因为对象的equels比较是比较两个对象的内存地址,所以除非是同一对象,否则equel返回永远是false。

但我们实际开发中 在我们的业务系统中判断对象时有时候需要的不是一种严格意义上的相等,而是一种业务上的对象相等。

在这种情况下,原生的equals方法就不能满足我们的需求了,所以这个时候我们需要重写equals方法。

说明 :String为什么可以使用equels方法为什么只要字符串相等就为true,那是因为String类重写了equal和hashCode方法,比较的是值。

1、Person对象
public class Person {
private String name;

    private Integer age;public Person(String name, Integer age) {this.name = name;this.age = age;}/*** 为什么重写equals方法一定要重写hashCode方法下面也会讲*/@Overridepublic int hashCode() {String result = name + age;return result.hashCode();}/*** 重写 equals 方法 根据name和age都相同那么对象就默认相同*/@Overridepublic boolean equals(Object obj) {Person u = (Person) obj;return this.getName().equals(u.getName()) && (this.age.equals(u.getAge()));}/*** 重写 toString 方法*/@Overridepublic String toString() {return "Person{" + "name='" + name + '\'' + ", age=" + age +'}';}}

2、测试
这里根据name和age都相同那么就默认相同对象。

  public static void main(String[] args) {List<Person> personList = Lists.newArrayList();Person person1 = new Person("小小",3);Person person2 = new Person("中中",4);personList.add(person1);personList.add(person2);List<Person> person1List = Lists.newArrayList();Person person3 = new Person("中中",4);Person person4 = new Person("大大",5);person1List.add(person3);person1List.add(person4);/*** 1、差集*/System.out.println(CollectionUtils.subtract(personList, person1List));//输出:[Person{name='小小', age=3}]/*** 2、并集*/System.out.println(CollectionUtils.union(personList, person1List));//输出:[Person{name='小小', age=3}, Person{name='中中', age=4}, Person{name='大大', age=5}]/*** 3、交集*/System.out.println(CollectionUtils.intersection(personList, person1List));//输出:[Person{name='中中', age=4}]/*** 4、交集的补集(析取)*/System.out.println(CollectionUtils.disjunction(personList, person1List));//输出:[Person{name='小小', age=3}, Person{name='大大', age=5}]}

其它两种方式就不在测了,因为都一样。

四、为什么重写equels方法一定要重写hashCode方法
1、源码
其实上面的Person类我可以只重写equels方法而不写hashCode方法,一样能达到上面的效果。

但为什么还是建议写上呢?官方的说法是:

对象的equals方法被重写,那么对象的hashCode()也尽量重写

重写equals()方法就必须重写hashCode()方法的原因,从源头Object类讲起就更好理解了。

先来看Object关于hashCode()和equals()的源码:

  public native int hashCode();public boolean equals(Object obj) {return (this == obj);}

光从代码中我们可以知道,hashCode()方法是一个本地native方法,返回的是对象引用中存储的对象的内存地址。

而equals方法是利用==来比较的也是对象的内存地址。

从上边我们可以看出,hashCode方法和equals方法是一致的。

如果equals方法返回false,hashcode可以不一样,但是这样不利于哈希表的性能,一般我们也不要这样做。

2、HashSet和Map集合类型
重写equals()方法就必须重写hashCode()方法主要是针对HashSet和Map集合类型,而对于List集合倒没什么影响。

原因:在向HashSet集合中存入一个元素时,HashSet会调用该对象(存入对象)的hashCode()方法来得到该对象的hashCode()值,然后根据该hashCode值决定该对象在HashSet中存储的位置。

简单的说:

HashSet集合判断两个元素相等的标准是:两个对象通过equals()方法比较相等,并且两个对象的HashCode()方法返回值也相等

如果两个元素通过equals()方法比较返回true,但是它们的hashCode()方法返回值不同,HashSet会把它们存储在不同的位置,依然可以添加成功。

3、代码示例
「1、People类」

重写equals方法,但并没有hashCode方法。public class People {private String name;private Integer age;public People(String name, Integer age) {this.name = name;this.age = age;}/*** 重写 equals 方法*/@Overridepublic boolean equals(Object obj) {People u = (People) obj;return this.getName().equals(u.getName()) && (this.age.equals(u.getAge()));}/*** 重写 toString 方法*/@Overridepublic String toString() {return "People{" + "name='" + name + '\'' +", age=" + age +'}';}
}

「2、实现类」

public static void main(String[] args) {HashSet<People> hashSet = Sets.newHashSet();People people1 = new People("小小",3);People people2 = new People("中中",4);People people3 = new People("中中",4);People people4 = new People("大大",5);hashSet.add(people1);hashSet.add(people2);hashSet.add(people3);hashSet.add(people4);System.out.println(hashSet);//输出:[People{name='小小', age=3}, People{name='中中', age=4}, People{name='大大', age=5}, People{name='中中', age=4}]
}

很明显,我重写了equals方法,那么people2和people3的equals应该相同,所以不能放入HashSet,但它们的hashCode()方法返回不同,所以导致同样能放入HashSet。

重点:对于Set集合必须要同时重写这两个方法,要不然Set的特性就被破坏了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/13217.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HDU - 4546 比赛难度(Java JS Python)

题目来源 Problem - 4546 (hdu.edu.cn) 题目描述 最近&#xff0c;小明出了一些ACM编程题&#xff0c;决定在HDOJ举行一场公开赛。 假设题目的数量一共是n道&#xff0c;这些题目的难度被评级为一个不超过1000的非负整数&#xff0c;并且一场比赛至少需要一个题&#xff0c;…

实战:Docker+Jenkins+Gitee构建CICD流水线

文章目录 前言Jenkins部署创建Jenkins docker-compose配置maven源启动Jenkins容器安装插件Gitee ssh公匙配置与测试项目提交 Jenkins创建流水线写在最后 前言 持续集成和持续交付一直是当下流行的开发运维方式&#xff0c;CICD省去了大量的运维时间&#xff0c;也能够提高开发…

ElasticSearch基本使用--ElasticSearch文章一

文章目录 官网学习必要性elasticsearch/kibana安装版本数据结构说明7.x版本说明ElasticSearch kibana工具测试后续我们会一起分析 官网 https://www.elastic.co/cn/ 学习必要性 1、在当前软件行业中&#xff0c;搜索是一个软件系统或平台的基本功能&#xff0c; 学习Elastic…

Git克隆文件不显示绿色勾、红色感叹号等图标

1、问题 Git和TorToiseGit安装后&#xff0c;Git克隆的文件不会显示绿色勾、红色感叹号等图标。 2、检查注册表 2.1、打开注册表 (1)WinR打开运行窗口&#xff0c;输入regedit&#xff0c;点击确定&#xff0c;打开注册表编辑器。 2.2、找如下路径 (1)找到路径 计算机\HKEY_…

linux----vim的使用

vi和vim是Linux下的一个文本编辑工具&#xff0c;最小化安装只有vi vim&#xff0c;需要额外安装&#xff0c;比vi更强大一些 # vim 操作文件&#xff0c;有三种模式&#xff1a;普通模式&#xff0c;编辑模式&#xff0c;命令模式 -vim 文件名刚进来----》普通模式--》只…

VBA技术资料MF34:检查Excel自动筛选是否打开

【分享成果&#xff0c;随喜正能量】聪明人&#xff0c;抬人不抬杠&#xff1b;傻子&#xff0c;抬杠不抬人。聪明人&#xff0c;把别人抬得很高&#xff0c;别人高兴、舒服了&#xff0c;看你顺眼了&#xff0c;自然就愿意帮你&#xff01;而傻人呢&#xff1f;不分青红皂白&a…

golang sync.singleflight 解决热点缓存穿透问题

在 go 的 sync 包中&#xff0c;有一个 singleflight 包&#xff0c;里面有一个 singleflight.go 文件&#xff0c;代码加注释&#xff0c;一共 200 行出头。内容包括以下几块儿&#xff1a; Group 结构体管理一组相关的函数调用工作,它包含一个互斥锁和一个 map,map 的 key 是…

Golang之路---01 Golang的安装与配置

Golang之路—01 Golang语言安装与配置 官网上下载Windows环境下的安装包 官网下载地址 双击下载后的文件进行安装&#xff0c;可根据需要自定义选择解压后的文件位置。 接着新创建一个文件夹&#xff0c;保存Golang语言项目。 在里面新建bin,pkg,src三个文件夹。 环境变量…

Verilog语法学习——LV4_移位运算与乘法

LV4_移位运算与乘法 题目来源于牛客网 [牛客网在线编程_Verilog篇_Verilog快速入门 (nowcoder.com)](https://www.nowcoder.com/exam/oj?page1&tabVerilog篇&topicId301) 题目 题目描述&#xff1a; 已知d为一个8位数&#xff0c;请在每个时钟周期分别输出该数乘1/…

Linux:Linux的发展史和作用有哪些?

文章目录 Linux是什么&#xff1f;Linux的开源特征为什么要学习Linux&#xff1f;Linux的应用场景有哪些&#xff1f; Linux是什么&#xff1f; 简单来说&#xff0c;Linux就是操作系统&#xff0c;它和Windows等软件一样&#xff0c;都只是操作系统&#xff0c;并无区别 Linu…

CSS的一些基础知识

选择器&#xff1a; 选择器用于选择要应用样式的HTML元素。常见的选择器包括标签选择器&#xff08;如 div、p&#xff09;、类选择器&#xff08;如 .class&#xff09;、ID选择器&#xff08;如 #id&#xff09;和伪类选择器&#xff08;如 :hover&#xff09;。选择器可以根…

webpack优化前端框架性能

webpack优化目的 webpack优化目的1. 提升开发体验提升开发体验使用 SourceMap 2. 提升打包构建速度提升打包构建速度&#xff08;开发模式&#xff09;提升打包速度 oneOf提升打包速度 include&#xff08;包含&#xff09;/exclude&#xff08;排除&#xff09;提升第二次打包…

爬虫-requests-cookie登录古诗文网

一、前言 1、requests简介 requests是一个很实用的Python HTTP客户端库&#xff0c;爬虫和测试服务器响应数据时经常会用到&#xff0c;它是python语言的第三方的库&#xff0c;专门用于发送HTTP请求&#xff0c;使用起来比urllib更简洁也更强大。 2、requests的安装 pip i…

电脑选睡眠、休眠还是关机?

关机 这是大家最熟悉的。关机时&#xff0c;系统首先关闭所有运行中的程序&#xff0c;然后关闭系统后台服务。随后&#xff0c;系统向主板请求关机&#xff0c;主板断开电源的供电使能&#xff0c;让电源切断对绝大多数设备的供电&#xff08;只剩一些内部零件仍会维持电源供应…

华为刷题:HJ3明明随机数

import java.util.Scanner;// 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main {public static void main(String[] args) {Scanner scan new Scanner(System.in);int N scan.nextInt();int[] arr new int[N];for (int i 0; i < N; i) {int n sca…

Materials - UE5中的PivotPainter

个人学习笔记的归档和发表&#xff1b;文中所有案例都来自官方的ContentExample中的PivotPainter相关关卡&#xff1b; 可以使用3DS Max Script中的脚本&#xff08;Pivot Painter&#xff09;对模型进行处理&#xff0c;让每个Element都有自己的Pivot Point&#xff0c;来方便…

PostgreSQL 简洁、使用、正排索引与倒排索引、空间搜索、用户与角色

PostgreSQL使用 PostgreSQL 是一个免费的对象-关系数据库服务器(ORDBMS)&#xff0c;在灵活的BSD许可证下发行。PostgreSQL 9.0 &#xff1a;支持64位windows系统&#xff0c;异步流数据复制、Hot Standby&#xff1b;生产环境主流的版本是PostgreSQL 12 BSD协议 与 GPL协议 …

SQL server 文件占用硬盘过大 日志 读写分离同步文件过大清理 DBCC收缩数据库 分发数据库distribution收缩

一顿操作猛如虎 又省出好几十G硬盘空间 小破站又能蹦跶了 目标&#xff1a;实例库日志压缩清理,分发数据库压缩清理 采用SQL 脚本收缩数据库 截断事务日志 backup log [数据库名] with no_log收缩数据库 dbcc shrinkdatabase ([数据库名]) 4.以上操作都不行的话&#xff0…

物联网场景中的边缘计算解决方案有哪些?

在物联网场景中&#xff0c;边缘计算是一种重要的解决方案&#xff0c;用于在物联网设备和云端之间进行实时数据处理、分析和决策。HiWoo Box作为工业边缘网关设备&#xff0c;具备边缘计算能力&#xff0c;包括单点公式计算、Python脚本编程以及规则引擎&#xff0c;它为物联网…

华为云NFS使用API删除大文件目录

最近在使用华为云SFS时&#xff0c;如果一个目录存储文件数超过100W&#xff0c;执行 “rm -rf path”时&#xff0c;存在删不动的情况&#xff0c;可以使用华为云API接口&#xff0c;执行异步删除。 华为官网&#xff1a; 删除文件系统目录_弹性文件服务 SFS_API参考_SFS Tu…