jdk 8新特性之 Stream 流的使用

这两天没有需求,在读项目中的代码,看到了有些用Stream流来操作集合的写法,特地学习总结,记录到博客里。首先是对stream流的介绍:

1、stream 流的介绍

Stream(流)是一个来自数据源的元素队列,元素是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。数据源:流的来源,可以是集合,数组 等。

和以前的Collection操作不同, Stream操作还有两个基础的特征:

Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道(pipline), 如同流式风格(fluentstyle)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。

内部迭代: 以前对集合遍历都是通过Iterator或者增强for的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式,流可以直接调用遍历方法。

出自:https://zhuanlan.zhihu.com/p/265884828

从上可以看出,流操作可以便利的进行迭代操作,对集合进行处理,那么该如何获得流呢,针对不同的类型,一般情况下有三种方式可以获得stream流,

2、如何获得一个stream流

如果需要构建的stream的集合来源于继承了collection类的类,如List,那么可以使用XXX.stream() 直接构建流。

        // 1、通过集合Collection获取
        //extends Collection<E> 的集合类型都可以通过该方法获取到
        List<Integer> list = Arrays.asList(1, 2, 4, 5, 6, 3, 9, 1);
        Stream<Integer> stream = list.stream();

如果需要构建stream的集合来源于数组,如String[] ,那么可以使用Arrays.stream(xxx) 可以得到stream流

        // 2、通过数组获取
        String[] arr = {"are", "you", "ok?"};
        Stream<String> stream1 = Arrays.stream(arr);
        int[] numArr = new int[]{1, 2, 5, 6, 3, 1};
        // 需要装箱操作,否则返回IntStream
        Stream<Integer> boxed = Arrays.stream(numArr).boxed();

如果需要构建stream的集合只有值,那么可以使用stream.of(xxx,xxx,xxx)直接构建

 // 3、通过值直接构建流
        Stream<String> stringStream = Stream.of("are", "you", "ok");

3、常用的stream操作

stream其基本思想是基于一次迭代尽可能多的对元素进行操作,设计并实现的,stream操作可以分为以下几类,分别为中间操作以及结束操作,不同操作的特征分类与特征如下所示:

filter 实现对元素的过滤,传入返回类型为boolean的lambda表达式

      // 常用管道操作 filter 接受一个lambda 表达式 返回类型为boolean
        // 流执行时,每个元素逐一进行筛选过滤,只有满足条件的才会到下一步
        List<String> collect = stringStream.filter(x -> !x.isEmpty())
                .filter(x -> x.length() > 2)
                .collect(Collectors.toList());
        collect.forEach(
                x -> System.out.println(x)
        );

distinct 去重,无传入

     // 去重 distinct
        List<Integer> collect1 = stream.distinct().collect(Collectors.toList());
        for (Integer integer : collect1) {
            System.out.println(integer);
        }

skip limited 截取元素,使用limited截取前若干个元素进入下一步;使用skip则是跳过若干个元素,进入下一步

        // 截取元素 limited
        List<String> collect2 = stream1.limit(1).collect(Collectors.toList());
        for (String s : collect2) {
            System.out.println(s);
        }
        // 截取元素 skip
        List<Integer> collect3 = boxed.skip(1).collect(Collectors.toList());
        for (Integer s : collect3) {
            System.out.println(s);
        }

map 映射,可以实现数据类型的转换,并执行下一步操作,或者直接输出

        // 映射 map 执行操作后转化为另外一种数据类型进行输出
        Stream<Integer> boxed1 = Arrays.stream(numArr).boxed();
        List<String> collect4 = boxed1.map(x -> String.valueOf(++x)).collect(Collectors.toList());
        collect4.forEach(x -> System.out.println(x));    

flatmap 实现多个流的合并

        // 合并多个流 flatMap
        List<Integer> integers1 = Lists.newArrayList(43, 2, 4, 5, 7);
        List<Integer> integers2 = Lists.newArrayList(2, 42, 4, 11, 1);
        List<List<Integer>> es = new ArrayList<>();
        es.add(integers1);
        es.add(integers2);
        List<Integer> collect5 = es.stream().flatMap(List::stream)
                .distinct()
                .sorted()
                .collect(Collectors.toList());

    collect5.forEach(x -> System.out.println(x));

匹配元素 allMatch anyMatch noneMatch 全部满足,任意一个满足,全不满足

需要传入boolean类型的lambda表达式

        // 匹配元素 anyMatch
        // 匹配元素 allMatch
        // 匹配元素 noneMatch
        Stream<Integer> integerStream = es.stream().flatMap(List::stream);
        Stream<Integer> integerStream1 = es.stream().flatMap(List::stream);
        Stream<Integer> integerStream2 = es.stream().flatMap(List::stream);
        boolean b1 = integerStream.anyMatch(x -> x > 0);
        boolean b2 = integerStream1.allMatch(x -> x > 5);
        boolean b3 = integerStream2.noneMatch(x -> x < 0);
        System.out.println(b1);
        System.out.println(b2);
        System.out.println(b3);

获取元素 findAny findFirst 前者返回任意一个满足要求的元素,需要传入返回类型为boolean的lambda表达式,findFirst 则是返回第一个元素

        // 获取元素 findAny
        // 获取元素 findFirst
        // 保证不是顺序流,返回才会随机
        Stream<Integer> parallel = Stream.of(2, 1, 3, 4).parallel();
        Optional<Integer> any = parallel.findAny();
        System.out.println("findAny测试,100次");
        // https://blog.csdn.net/qq_31635851/article/details/111178278
        for (int i = 0; i < 100; i++) {
            Stream.of(10, 20, 30).parallel().findAny()
                    .ifPresent(s -> System.out.println(s));
        }
        boolean present = any.isPresent();
        if (present) {
            Integer integer = any.get();
            System.out.println(integer);
        }
        Stream<Integer> integerStream3 = es.stream().flatMap(List::stream);
        Optional<Integer> first = integerStream3.findFirst();
        if (first.isPresent()) {
            System.out.println(first.get());
        }

注:当操作的流不是并行流,会导致findAny每次返回的都是同一个元素,需要转化为并行流,才会随机返回元素。

Stream流转换为其他数据类型 如Collection Array String

        //普通转换
        Stream<String> stringStream1 = Stream.of("are", "you", "ok");
        Object[] array1 = stringStream1.toArray();
        for (Object s : array1) {
            System.out.println(s.toString());
        }

        //涉及拆箱、装箱操作的转换
        Stream<Integer> stream12 = Stream.of(1, 2, 3, 4, 5, 6);
        int[] array12 = stream12.mapToInt(x -> x).toArray();
        // Integer[] array13 = stream12.toArray(Integer[]::new);
        for (Integer integer : array12) {
            System.out.println(integer);
        }

        //将 List<Inetegr> 转化为 String[]
        List<Integer> list12 = Arrays.asList(1, 2, 3, 4, 5);
        String[] array = list12.stream().map(String::valueOf).toArray(String[]::new);
        for (String s : array) {
            System.out.println(s);
        }
        // Stream -> List
        List<Integer> list1 = stream.collect(Collectors.toList());
        List<Integer> list2 = stream.collect(Collectors.toCollection(ArrayList::new));
        // Stream ->Set
        Set<Integer> set = stream.collect(Collectors.toCollection(HashSet::new));
        // Stream -> stack
        Stack<Integer> stack = stream.collect(Collectors.toCollection(Stack::new));
        // Stream ->map
        Map<Integer, String> map = Stream.of("are", "you", "ok")
                .collect(Collectors.toMap(s -> s.hashCode(), s -> s));
        // Stream -> String

        //将 List 转化为使用 “,” 分隔的字符串
        List<Integer> list3 = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
        String str = list3.stream().map(x -> x.toString()).collect(Collectors.joining(","));
        System.out.println(str);

注:代码中出现的 :: 为lambda表达式引用类构造的方法的便捷写法,等价于 new 一个对应的对象。

出处:https://blog.csdn.net/Al_assad/article/details/82356845

posted @ 2022-09-13 20:09  charler。  阅读(137)  评论(0编辑  收藏  举报