Java 8 Stream流处理


参考文献:

https://blog.csdn.net/weixin_37948888/article/details/96995312

https://blog.csdn.net/mmlz00/article/details/86247998

https://www.cnblogs.com/CarpenterLee/p/6637118.html

https://www.cnblogs.com/CarpenterLee/p/6545321.html

https://www.cnblogs.com/CarpenterLee/p/6550212.html

https://www.runoob.com/java/java8-streams.html

1 什么是 Stream?

Stream(流) 是一个来自数据源的元素队列并支持聚合操作.

  • 元素 是特定类型的对象,形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
  • 数据源 流的来源。 可以是集合,数组,I/O channel, 产生器generator 等。
  • 聚合操作 类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。

Stream操作还有两个基础的特征:

  • Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
  • 内部迭代: 以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。

2 Stream的API

常见API总结:

扫描二维码关注公众号,回复: 12658796 查看本文章
操作类型 接口方法
中间操作 concat() distinct() filter() flatMap() limit() map() peek() skip() sorted() parallel() sequential() unordered()
结束操作 allMatch() anyMatch() collect() count() findAny() findFirst()
forEach() forEachOrdered() max() min() noneMatch() reduce() toArray()

区分中间操作和结束操作的方法,就是看方法的返回值,返回值为stream的是中间操作,否则是结束操作.

1 生成流

stream() − 为集合创建串行流

    @Test
    public void test(){
    
    
        List<String> oldList = Arrays.asList("小红", "小蓝", "小粉", "小红", "小白", "小灰", "小青", "");
        List<String> newList = oldList.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());
        System.out.println(newList);
    }
    
    //结果 过滤为空的元素
    //[小红, 小蓝, 小粉, 小红, 小白, 小灰, 小青]

parallelStream() − 为集合创建并行流

并行流就是把一个内容分成多个数据块,并用不同的线程分别处理每个数据块的流

引入: Fork/Join框架

不同的数据结构,使用parallel stream的性能不同

性能 数据结构
Best ArrayList [Concurrent]HashMaps plain arrays(阵列)
Middle
Worst LinkedList BlockingQueues most IO-based sources
    @Test
    public void test() {
    
    
        List<String> strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
        // 获取空字符串的数量
        long count = strings.parallelStream().filter(string -> string.isEmpty()).count();
        System.out.println(count);

        /* 结果
            2
        */
    }

2 forEach

Stream 提供了新的方法 forEach来迭代流中的每个数据.

    @Test
    public void test(){
    
    
        Random random = new Random();
        random.ints().limit(10).forEach(System.out::println);
    }

    /* 结果
    953463696
    904482529
    1992227049
    228289483
    1260884019
    -694492700
    -1895609817
    390932419
    222813973
    1720446195
    */

3 map

map 方法用于映射每个元素到对应的结果.

    @Test
    public void test(){
    
    
        List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);
        // 获取对应的平方数
        List<Integer> squaresList = numbers.stream().map( i -> i*i).distinct().collect(Collectors.toList());
        System.out.println(squaresList);
        //结果
        //[9, 4, 49, 25]
    }

4 flatMap

用于把原stream中的所有元素都"摊平"之后组成的Stream,转换前后元素的个数和类型都可能会改变.

    @Test
    public void test() {
    
    
        Stream<List<String>> stream = Stream.of(Arrays.asList("java", "python"), Arrays.asList("go","c", "c#"));
        stream.flatMap(list -> list.stream())
                .forEach(i -> System.out.println(i));
        
        /* 结果
            java
            python
            go
            c
            c#
        */
    }

5 filter

filter 方法用于通过设置的条件过滤出元素.

    @Test
    public void test(){
    
    
        List<String>strings = Arrays.asList("abc", "", "bc", "efg", "abcd","", "jkl");
        // 获取空字符串的数量
        long count = strings.stream().filter(string -> string.isEmpty()).count();
        System.out.println(count);
        //结果
        //2
    }

6 distinct

作用是返回一个去除重复元素.

    @Test
    public void test() {
    
    
        Stream<String> stream= Stream.of("java", "python", "c++", "java", "python");
        stream.distinct()
                .forEach(str -> System.out.println(str));

        /* 结果
            java
            python
            c++
        */
    }

7 sorted

sorted 方法用于对流进行排序.

  • 自然顺序排序 Stream<T> sorted()
  • 自定义比较器排序 Stream<T> sorted(Comparator<? super T> comparator)
    @Test
    public void test() {
    
    
        Random random = new Random();
        //自然顺序排序
        random.ints().limit(10).sorted().forEach(System.out::println);

        //自定义比较器排序
        Stream<String> stream= Stream.of("I", "love", "you", "too");
        stream.sorted((str1, str2) -> str1.length()-str2.length())
                .forEach(str -> System.out.println(str));
        /* 结果
            -1333606821
            -1309783057
            -925151692
            -151014012
            326091384
            631640690
            931593578
            1222302927
            1666642944
            1787379588
            I
            you
            too
            love
        */
    }

8 limit

limit 方法用于获取指定数量的流.

    @Test
    public void test() {
    
    
        Random random = new Random();
        random.ints().limit(10).forEach(System.out::println);
        
        /* 结果     
        590073840
        1940673188
        14366652
        - 1137645939
        1597476888
        1548777482
        198110723
        1269388780
        - 1953509555
        - 1577770188
        */
    }

9 reduce

reduce操作可以实现从一组元素中生成一个值,sum()max()min()count()等.

  • Optional<T> reduce(BinaryOperator<T> accumulator)
  • T reduce(T identity, BinaryOperator<T> accumulator)
  • <U> U reduce(U identity, BiFunction<U,? super T,U> accumulator, BinaryOperator<U> combiner)
    @Test
    public void test() {
    
    

        //查询字符长度最长的字符
        Stream<String> stream = Stream.of("java", "python", "c", "c++","c#");
        Optional<String> longest = stream.reduce((s1, s2) -> s1.length()>=s2.length() ? s1 : s2);
        //Optional<String> longest = stream.max((s1, s2) -> s1.length()-s2.length());
        System.out.println(longest.get());

        /* 结果
            python
        */
    }


    @Test
    public void test() {
    
    

        // 求单词长度之和
        Stream<String> stream = Stream.of("java", "python", "c", "c++","c#");

        Integer lengthSum = stream.reduce(0, //初始值
        (sum, str) -> sum+str.length(), //累加器
                (a, b) -> a+b); //部分和拼接器,并行执行

        // int lengthSum = stream.mapToInt(str -> str.length()).sum();
        System.out.println(lengthSum);

        /* 结果
            16
        */
    }

10 collect

用于将Stream转换成容器的方法.

1 生成Collection

Stream转换成List或Set

    @Test
    public void test() {
    
    

        Stream<String> stream = Stream.of("java", "python", "c", "c++","c#");
        Stream<String> stream1 = Stream.of("java", "python", "c", "c++","c#");
        List<String> list = stream.collect(Collectors.toList());
        Set<String> set = stream1.collect(Collectors.toSet());

        System.out.println(list);
        System.out.println(set);
        /* 结果
            [java, python, c, c++, c#]
            [c#, python, c++, java, c]
        */
    }

指定容器的实际类型Collectors.toCollection(Supplier<C> collectionFactory)

    @Test
    public void test() {
    
    

        Stream<String> stream = Stream.of("java", "python", "c", "c++","c#");
        Stream<String> stream1 = Stream.of("java", "python", "c", "c++","c#");
        ArrayList<String> arrayList = stream.collect(Collectors.toCollection(ArrayList::new));
        HashSet<String> hashSet = stream1.collect(Collectors.toCollection(HashSet::new));

        System.out.println(arrayList);
        System.out.println(hashSet);
        /* 结果
            [java, python, c, c++, c#]
            [c#, python, c++, java, c]
        */
    }

2 生成Map

  • Collectors.toMap() 指定如何生成Mapkeyvalue
  • Collectors.partitioningBy() 对元素进行二分区操作时用到
  • Collectors.groupingBy() 对元素做group操作时用到

Collectors.toMap

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class User {
    
    
       private String id;
       private String name;
       private Integer age;
       private String sex;
    }
    @Test
    public void test() {
    
    
		//1 指定key-value,value是对象中的某个属性值
		 Map<Integer,String> userMap1 = userList.stream().collect(Collectors.toMap(User::getId,User::getName));
        
        //2 指定key-value,value是对象本身
        Map<Integer,User> userMap2 = userList.stream().collect(Collectors.toMap(User::getId,User->User));
        
        //3 指定key-value,value是对象本身,Function.identity()是简洁写法,返回对象本身
        Map<Integer,User> userMap3 = userList.stream().collect(Collectors.toMap(User::getId, Function.identity()));
        
        //4 指定key-value,value是对象本身,Function.identity()是简洁写法,返回对象本身,key 冲突的解决办法,这里选择新的key覆盖旧的key
         Map<Integer,User> userMap4 = userList.stream().collect(Collectors.toMap(User::getId, Function.identity(),(key1,key2)->key2));
        
    }

Collectors.partitioningBy()

用于将Stream中的元素依据某个二值逻辑(满足条件,或不满足)分成互补相交的两部分,如男女性别,及格与否

    @Test
    public void test() {
    
    
		Map<Boolean, List<User>> userMap5 = userList.stream().collect(Collectors.partitioningBy(s -> s.getAge() >= 40));
    }

Collectors.groupingBy()

按照某个属性对数据进行分组,属性相同的元素会被对应到Map的同一个key上.

	@Test
    public void test() {
    
    
        //根据男女分组,分别统计两组的人数
		Map<String, Integer> totalByDept = userList.stream()
                    .collect(Collectors.groupingBy(User::getSex(),
                                                   Collectors.counting()));// 下游收集器
    }

	//下游收集器中还可以包含更下游的收集器
	@Test
    public void test() {
    
    
        //根据男女分组,并统计两组的所有人员名称
		Map<String,List<String>> totalByDept = userList.stream()
                    .collect(Collectors.groupingBy(User::getSex(),
                                Collectors.mapping(User::getName,// 下游收集器
                                Collectors.toList())));// 更下游的收集器
    }

3 字符串join

字符串拼接时使用Collectors.joining()生成的收集器

    @Test
    public void test() {
    
    

        // 使用Collectors.joining()拼接字符串
        Stream<String> stream = Stream.of("I", "love", "you");
        // String joined1 = stream.collect(Collectors.joining());
        // System.out.println(joined1);
        // String joined2 = stream.collect(Collectors.joining(","));
        // System.out.println(joined2);
        String joined3 = stream.collect(Collectors.joining(",", "{", "}"));
        System.out.println(joined3);

            /*结果
            Iloveyou
            I,love,you
            {I,love,you}
            */

    }

11 统计

一些产生统计结果的收集器也非常有用。主要用于int、double、long等基本类型上.

    @Test
    public void test() {
    
    
        List<Integer> numbers = Arrays.asList(3, 2, 2, 3, 7, 3, 5);

        IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics();

        System.out.println("列表中最大的数 : " + stats.getMax());
        System.out.println("列表中最小的数 : " + stats.getMin());
        System.out.println("所有数之和 : " + stats.getSum());
        System.out.println("平均数 : " + stats.getAverage());

        /* 结果
            列表中最大的数 : 7
            列表中最小的数 : 2
            所有数之和 : 25
            平均数 : 3.5714285714285716
        */
    }

猜你喜欢

转载自blog.csdn.net/ABestRookie/article/details/114265838