Java进阶(不可变集合和Stream流)

1. 创建不可变集合的应用场景

  • 如果某个数据不能被修改,把它防御性地拷贝到不可变集合中是个很好的实践
  • 或者当集合对象被不可信的库调用时,不可变形式是安全的

image-20221225140039955

例如,制定游戏规则。

image-20221225140137174

又如,电脑的配置,这些都是不可变集合的应用场景。

1.1 创建不可变集合List

List<String> list = List.of("zs", "lisi", "wangwu");
        for (String item : list) {
            System.out.println(item);
        }
        list.remove("zs");

结果如下:只能进行查询,不能进行添加或者删除操作

image-20221225142024326

1.2 创建不可变结合Set

Set<String> set = Set.of("zs", "lisi", "wangwu");
        for (String item : set) {
            System.out.println(item);
        }
        set.remove("zs");

结果如下:依然报错是无法修改,而且set集合元素不能重复的规则同样适用

image-20221225142537391

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个键值对

image-20221225143626806

但是我们可以采用另外一个方法,即

image-20221225144242537

如果我们用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");

如果向不可变集合中试图添加数据,则会报错

image-20221225145844501

当然上面的代码过于繁琐,java已经帮我们封装好了。

image-20221225150326087

因此我们可以在map上直接调用copyOf方法,当然结果都是不可修改

  Map<String, String> map1 = Map.copyOf(map);
        map1.put("11","io");

image-20221225150412239

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));

打印结果如下:

image-20221225153824009

我们可以看到采用stream流可以用最少的代码来完成需求。

2.1 Stream流的思想

image-20221225154902194

可以类比如果的流水线,在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+" "));

image-20221225160321976

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));

image-20221226101604357

2.1.3 数组

数组可以通过调用Arrays工具类中的静态方法stream()

 int []arr={1,2,3,4,5};
 Arrays.stream(arr).forEach(item-> System.out.println(item));

image-20221226102018273

2.1.4 一堆零散数据

通过调用Stream接口的静态方法of()实现

  Stream.of("1","abc",2,4,1.56,true).forEach(item-> System.out.println(item));

image-20221226102951844

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);

image-20221226104138141

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);

image-20221226104703931

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));

image-20221226104916758

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));

image-20221226105152577

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+" "));

image-20221226105434435

2.3 Stream流的终结方法

2.3.1 forEach

遍历流中每个元素

    ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"yh","pzr","zs");
        list.stream().forEach(System.out::println);

image-20221226110552740

2.3.2 count

统计流中的元素个数

 ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"yh","pzr","zs");
        long count = list.stream().count();
        System.out.println(count);

image-20221226110654255

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));

image-20221226112217922

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);

image-20221226194904371

如果是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);

image-20221226195326067

如果是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);

image-20221226212100207

最后修改:2022 年 12 月 28 日
如果觉得我的文章对你有用,请随意赞赏