当前位置: 首页 > news >正文

Day30 | Java集合框架之Collections工具类

Day26~29的文章我们一起学习了Java集合框架的三大核心接口:List、Set和Map。

今天我们一起看一下java.util.Collections类,注意不是之前我们提到的Collection。

Collection接口定义了集合的是什么,多了个s的Collections是一套集合操作的工具箱。

Collections里提供了很多强大、方便的静态方法,能极大简化我们对集合的操作。

一、集合排序

在实际开发中,对数据进行排序是最常见的需求之一。Collections.sort() 方法可以轻松地对任何List集合进行排序。

1.1自然排序

如果List里的元素实现了Comparable接口(如Integer, String 等),sort方法会按照它们的自然顺序进行排序。

package com.lazy.snail.day30;import java.util.ArrayList;
import java.util.Collections;
import java.util.List;/*** @ClassName Day30Demo* @Description TODO* @Author lazysnail* @Date 2025/7/7 15:13* @Version 1.0*/
public class Day30Demo {public static void main(String[] args) {List<Integer> numbers = new ArrayList<>();numbers.add(5);numbers.add(1);numbers.add(9);numbers.add(3);System.out.println("排序前: " + numbers);Collections.sort(numbers);System.out.println("排序后: " + numbers);}
}

 

案例中使用了Collections的sort方法,使用对象的自然排序对list进行排序。

1.2自定义排序

如果我们要对自定义对象(如Student)进行排序,sort方法还有一个接受Comparator(比较器)的版本,让我们可以随心所欲地定义排序规则。

package com.lazy.snail.day30;import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;/*** @ClassName Day30Demo2* @Description TODO* @Author lazysnail* @Date 2025/7/7 15:21* @Version 1.0*/
public class Day30Demo2 {public static void main(String[] args) {List<Student> students = new ArrayList<>();students.add(new Student("懒惰蜗牛", 28));students.add(new Student("lazysnail", 29));// 匿名内部类写法Collections.sort(students, new Comparator<Student>() {@Overridepublic int compare(Student o1, Student o2) {return o1.age - o2.age;}});// Lambda表达式Collections.sort(students, (o1, o2) -> o1.age - o2.age);// Comparator工具方法Collections.sort(students, Comparator.comparingInt(o -> o.age));System.out.println("按年龄排序后: " + students);}
}class Student {String name;int age;public Student(String name, int age) { this.name = name; this.age = age; }@Override public String toString() { return name + ":" + age; }
}

上面的案例中Comparator的创建使用了三种写法:

Java8之前传统写法,使用匿名内部类实现Comparator接口。

Java8+的Lambda表达式,这个其实是匿名内部类的语法糖。

Comparator<Student>接口是一个函数式接口(只有一个抽象方法),所以可以用Lambda替代。

Comparator.comparingInt()是Comparator提供的静态工厂方法,专门用来对int类型字段的比较。

内部封装了compare的逻辑。

其实自Java8之后,List接口自身提供了一个sort()方法。可以直接在列表对象上调用方法。

students.sort((o1, o2) -> o1.age - o2.age);

 

二、查找

对于一个已经排好序的List,binarySearch方法使用二分查找算法,效率要高于遍历。

使用binarySearch之前,列表必须是有序的!否则,结果就不是你想要的。

效率

package com.lazy.snail.day30;import java.util.ArrayList;
import java.util.Collections;
import java.util.List;/*** @ClassName Day30Demo3* @Description TODO* @Author lazysnail* @Date 2025/7/7 15:52* @Version 1.0*/
public class Day30Demo3 {public static void main(String[] args) {List<Integer> list = new ArrayList<>();for (int i = 0; i < 1_000_000; i++) {list.add(i);}int target = 987654;// 遍历long start1 = System.nanoTime();for (int i = 0; i < list.size(); i++) {if (list.get(i) == target) {break;}}long end1 = System.nanoTime();System.out.println("遍历查找耗时: " + (end1 - start1) / 1_000_000.0 + " ms");// binarySearchlong start2 = System.nanoTime();Collections.binarySearch(list, target);long end2 = System.nanoTime();System.out.println("binarySearch查找耗时: " + (end2 - start2) / 1_000_000.0 + " ms");}
}

 

从运行的结果看,二分查找的效率比普通遍历的效率高得多。

二分查找这种算法,每次都能排除掉一半的数据。相较于普通遍历的线性搜素。

在数据量很多的情况下,二分查找的时间复杂度要远远低于普通遍历。

未排序使用binarySearch

如果对没有排序的列表进行二分查找,结果就是找不到数据。

package com.lazy.snail.day30;import java.util.Arrays;
import java.util.Collections;
import java.util.List;/*** @ClassName Day30Demo4* @Description TODO* @Author lazysnail* @Date 2025/7/7 16:08* @Version 1.0*/
public class Day30Demo4 {public static void main(String[] args) {List<Integer> list = Arrays.asList(50, 20, 40, 10, 30);System.out.println("列表内容: " + list);// 想查找元素 30int index = Collections.binarySearch(list, 30);System.out.println("binarySearch 查找结果索引: " + index);}
}

 

三、线程安全转换

我们经常用的ArrayList、HashMap等都是非线程安全的。

在多线程环境中并发修改,可能会导致数据错乱。

Collections提供了一系列synchronizedXXX() 方法,可以把它们包装成线程安全的集合。

 

package com.lazy.snail.day30;import java.util.*;/*** @ClassName Day30Demo5* @Description TODO* @Author lazysnail* @Date 2025/7/7 16:26* @Version 1.0*/
public class Day30Demo5 {public static void main(String[] args) {List<String> list = new ArrayList<>();List<String> safeList = Collections.synchronizedList(list);safeList.add("懒惰蜗牛");//Set<T> safeSet = Collections.synchronizedSet(new HashSet<>());//Map<K, V> safeMap = Collections.synchronizedMap(new HashMap<>());}
}

list是线程不安全的ArrayList,通过Collections中的synchronizedList方法。

将普通的ArrayList封装成了线程安全的List。之后对list的操作就是安全的。

set、map同样有对应的方法将不安全的集合封装成线程安全的集合。

需要注意的是:这个操作只保证了单个方法(如add, get)是原子的。对于复合操作(比如“检查是否存在,如果不存在则添加”),仍然需要自己使用synchronized关键字来保证整个操作的原子性。

四、创建不可变和空集合

不可变

有时候,我们想创建一个不可变的集合,这个集合不让修改。就可以用Collections中的unmodifiableXXX()方法创建只读的集合。

 

package com.lazy.snail.day30;import java.util.ArrayList;
import java.util.Collections;
import java.util.List;/*** @ClassName Day30Demo6* @Description TODO* @Author lazysnail* @Date 2025/7/7 16:56* @Version 1.0*/
public class Day30Demo6 {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("懒惰蜗牛");List<String> unmodifiableList = Collections.unmodifiableList(list);//unmodifiableList.add("lazysnail");unmodifiableList.remove("懒惰蜗牛");}
}

如果想对这样的集合进行add或remove等操作,就会抛出UnsupportedOperationException异常。

从Java9开始,List, Set, Map接口自身提供了更方便的静态of()方法来直接创建真正的不可变集合。

这种方式在实际开发中更加常见。

为什么说是真正的不可变呐。回看上面的案例,稍作一下修改:

package com.lazy.snail.day30;import java.util.ArrayList;
import java.util.Collections;
import java.util.List;/*** @ClassName Day30Demo6* @Description TODO* @Author lazysnail* @Date 2025/7/7 16:56* @Version 1.0*/
public class Day30Demo6 {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("懒惰蜗牛");List<String> unmodifiableList = Collections.unmodifiableList(list);System.out.println("原集合修改前的unmodifiableList:" + unmodifiableList);list.add("lazysnail");System.out.println("原集合修改后的unmodifiableList:" + unmodifiableList);}
}

可以看出,unmodifiableList并没有改变原集合的可变性,只是加了一层只读外壳。

如果原集合一旦被外部引用持有,仍然可以修改。

而List.of(...) 是真正的不可变对象,内部结构不允许任何修改操作。

所有变更操作(add、remove、set)都会直接抛UnsupportedOperationException。

List<String> list1 = List.of("懒惰蜗牛");
list1.add("lazysnail");

"list1.add("lazysnail");"就会抛出UnsupportedOperationException。

空集合

很多返回集合的方法,如果直接返回null,保不准什么时候就会报空指针异常。

实际开发的时候,最好还是返回一个空集合。

Collections的emptyList(), emptySet(), emptyMap()就派上了用场。

package com.lazy.snail.day30;import java.util.Collections;
import java.util.List;/*** @ClassName Day30Demo7* @Description TODO* @Author lazysnail* @Date 2025/7/7 17:14* @Version 1.0*/
public class Day30Demo7 {public static List<String> findUsers(String name) {// if 找到// elsereturn Collections.emptyList();}
}

可能你会说,为什么不直接return的时候直接new ArrayList<>()。

每次return的时候,都去new一个对象,还是有开销的,能省则省。

Collections的emptyList()返回的是一个不可变的、线程安全的、可被序列化的空集合。

每次返回的都是同一个静态实例。

 

五、其他

Collections中还有很多其他的小工具:

reverse(List<?> list): 反转List中元素的顺序。

shuffle(List<?> list): 随机打乱List中元素的顺序。

max(Collection<?> coll) / min(Collection<?> coll): 找到集合中的最大/最小元素。

fill(List<?> list, T obj): 用指定元素替换List中的所有元素。

更多的方法参见API文档:

Collections (Java SE 17 & JDK 17)docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Collections.html

结语

Collections中有非常多关于集合的操作工具。

今天我们只是一起看了一下排序、查找、线程安全、创建不可变集合等常见的功能。

这些工具都能够在实际开发中帮我们让代码更加简洁,让集合操作更加便捷高效。

Collections里的方法不需要取死记硬背,在写代码的时候,如果涉及操作集合,

可以翻看一下API文档,如果有合适的工具,使用即可。

下一篇预告

Day31 | Lambda表达式与函数式接口

如果你觉得这系列文章对你有帮助,欢迎关注专栏,我们一起坚持下去!

本文首发于知乎专栏

http://www.dtcms.com/a/430628.html

相关文章:

  • 【STM32项目开源】基于STM32的智能养殖场环境监测系统
  • 【Java并发】揭秘Lock体系 -- condition等待通知机制
  • 计算机网络-网络边缘网络核心
  • 安卓13_ROM修改定制化-----修改固件 去除主题防止恢复 破解主题等操作解析
  • 怎么做网站301重定向可口可乐公司的企业网站建设
  • NS4168输出音频通过ESP32C3测试
  • 24.使用 HTML 和 CSS 实现无限旋转正方形动画效果
  • 音频降噪技术:从原理到工具的完整指南(scipy librosa noisereduce soundfile pedalboard)
  • 网站建设构成技术要求wordpress书籍推荐
  • CoCoSim(2020): 连接Simulink与Lustre生态的模型检测框架
  • 第2篇|风机设计的基本原则:从“会弯的高楼”到“会自救的系统”
  • SpringSecurity详解
  • [linux仓库]深入解析Linux动态链接与动态库加载:理解背后的原理与技巧
  • 异步日志系统
  • 自监督学习在医疗AI中的技术实现路径分析(中)
  • QoS之拥塞管理两种配置方法
  • tp框架做网站的优点郑州品牌策划设计公司
  • 浅析 AC 自动机
  • Docker常见问题与解决
  • Rokid手势识别技术深度剖析
  • java web搭建商城购物车
  • 从 0 到 1 搭建 Python 语言 Web UI自动化测试学习系列 6--基础知识 2--常用元素定位 2
  • 从“端到端”到“人到人”:一种以需求直接满足为核心的新一代人机交互范式
  • C到C++(Num015)
  • 做关于车的网站有哪些网页布局的方式有哪些
  • 图漾相机C++语言---Sample_V1(4.X.X版本)完整参考例子(待完善)
  • Python数据挖掘之基础分类模型_支持向量机(SVM)
  • Java-Spring 入门指南(十六)SpringMVC--RestFul 风格
  • 益阳网站制作公司地址高端装饰公司网站设计
  • 产生式规则在自然语言处理深层语义分析中的演变、影响与未来启示