Java进阶(不可变集合和Stream流)
1. 创建不可变集合的应用场景
- 如果某个数据不能被修改,把它防御性地拷贝到不可变集合中是个很好的实践
- 或者当集合对象被不可信的库调用时,不可变形式是安全的
例如,制定游戏规则。

又如,电脑的配置,这些都是不可变集合的应用场景。
1.1 创建不可变集合List
List<String> list = List.of("zs", "lisi", "wangwu");
for (String item : list) {
System.out.println(item);
}
list.remove("zs");
结果如下:只能进行查询,不能进行添加或者删除操作
1.2 创建不可变结合Set
Set<String> set = Set.of("zs", "lisi", "wangwu");
for (String item : set) {
System.out.println(item);
}
set.remove("zs");
结果如下:依然报错是无法修改,而且set集合元素不能重复的规则同样适用
1.3 创建不可变Map
Map<String, String> map = Map.of("张三", "重庆", "李四", "成都", "王五", "海南");
Set<String> keySet = map.keySet();
for (String key : keySet) {
System.out.println(key+"=="+map.get(key));
}
结果如下,注意1:map依然不能键重复;注意2:Map的of方法最多只能容纳10个键值对
但是我们可以采用另外一个方法,即
如果我们用entry来作为可变形参,就可以解决of方法的参数限制问题。
Map<String, String> map = Map.of("张三", "重庆", "李四", "成都", "王五", "海南");
Set<Map.Entry<String, String>> entries = map.entrySet();
//将entries变成一个数组
Map.Entry[] arr = entries.toArray(new Map.Entry[0]);
Map ofEntries = Map.ofEntries(arr);
for (Object o : ofEntries.entrySet()) {
System.out.println(o);
}
//不可变map集合
ofEntries.put("111","bbb");
如果向不可变集合中试图添加数据,则会报错
当然上面的代码过于繁琐,java已经帮我们封装好了。
因此我们可以在map上直接调用copyOf方法,当然结果都是不可修改
Map<String, String> map1 = Map.copyOf(map);
map1.put("11","io");
2. Stream流
一个基本的demo如下,假设有如下两个需要同时满足的需求
- 获取以‘z’开头的字符串
- 获取长度为3的字符串
ArrayList<String> list = new ArrayList<>();
list.add("zs");
list.add("zwr");
list.add("lisi");
list.add("wangwu");
list.stream().filter(name->name.startsWith("z")).filter(name->name.length()==3).forEach(name-> System.out.println(name));
打印结果如下:
我们可以看到采用stream流可以用最少的代码来完成需求。
2.1 Stream流的思想
可以类比如果的流水线,在Stream流的思想中就是层层筛选,最终得到想要的结果
2.1.1 单列集合
ArrayList<Integer> list = new ArrayList<>();
Collections.addAll(list,1,9,3,7,5);
list.stream().forEach(s-> System.out.print(s+" "));
2.1.2 双列集合
在map中是没有stream()方法直接获取流,因此我们可以先将map转化为entry集合,再调用Stream()方法。
HashMap<String, String> map = new HashMap<>();
map.put("111","aaa");
map.put("222","bbb");
map.put("333","ccc");
map.entrySet().stream().forEach(entry-> System.out.println(entry));
2.1.3 数组
数组可以通过调用Arrays工具类中的静态方法stream()
int []arr={1,2,3,4,5};
Arrays.stream(arr).forEach(item-> System.out.println(item));
2.1.4 一堆零散数据
通过调用Stream接口的静态方法of()实现
Stream.of("1","abc",2,4,1.56,true).forEach(item-> System.out.println(item));
2.2 Stream流的中间方法
2.2.1 Filter
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"zs","lisi","wu","zl","hy","hjy");
list.stream().filter(s-> s.startsWith("z")).forEach(System.out::println);
2.2.2 limit
获取流的前几个元素
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"zs","lisi","wu","zl","hy","hjy");
list.stream().limit(3).forEach(System.out::println);
2.2.3 skip
跳过流的前几个元素
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"zs","lisi","wu","zl","hy","hjy");
list.stream().skip(4).forEach(s-> System.out.println(s));
2.2.4 distinct
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"zs","lisi","zs","zl","hy","hjy","zs");
list.stream().distinct().forEach(s-> System.out.println(s));
2.2.5 concat
Stream接口的静态方法concat(),用来合并两个stream流
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"zs","lisi","zs","zl","hy","hjy","zs");
ArrayList<Integer> list2 = new ArrayList<>();
Collections.addAll(list2,1,2,3,4);
Stream.concat(list.stream(),list2.stream()).forEach(s-> System.out.print(s+" "));
2.3 Stream流的终结方法
2.3.1 forEach
遍历流中每个元素
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"yh","pzr","zs");
list.stream().forEach(System.out::println);
2.3.2 count
统计流中的元素个数
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"yh","pzr","zs");
long count = list.stream().count();
System.out.println(count);
2.3.3 toArray
value指元素个数
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"yh","pzr","zs");
String[] array = list.stream().toArray(value -> new String[value]);
System.out.println(Arrays.toString(array));
2.3.4 collect
//需求:收集男性角色
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"yh-男","pzr-男","zs-女");
List<String> collect = list.stream()
.filter(s->"男".equals(s.split("-")[1]))
.collect(Collectors.toList());
System.out.println("collect = " + collect);
如果是toSet(),则会自动去重,如下:
//需求:收集男性角色
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"yh-男","pzr-男","pzr-男","zs-女");
Set<String> collect = list.stream()
.filter(s->"男".equals(s.split("-")[1]))
.collect(Collectors.toSet());
System.out.println("collect = " + collect);
如果是toMap
ArrayList<String> list = new ArrayList<>();
Collections.addAll(list,"yh-男","pzr-男","pzer-男","zs-女");
Map<String, String> collect = list.stream()
.filter(s -> "男".equals(s.split("-")[1]))
.collect(Collectors.toMap(k -> k.split("-")[0], v -> v.split("-")[1]));
System.out.println(collect);