jdk8新特性-Stream流详解及使用样例(Stream创建使用收集并行流注意事项)

Posted 、Dong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了jdk8新特性-Stream流详解及使用样例(Stream创建使用收集并行流注意事项)相关的知识,希望对你有一定的参考价值。


前言

注意:Stream和IO流(InputStream/OutputStream)没有任何关系,请暂时忘记对传统IO流的固有印象!
Stream流式思想类似于工厂车间的“生产流水线”,Stream流不是一种数据结构,不保存数据,而是对数据进行加工
处理。Stream可以看作是流水线上的一个工序。在流水线上,通过多个工序让一个原材料加工成一个商品。
Stream API能让我们快速完成许多复杂的操作,如筛选、切片、映射、查找、去除重复,统计,匹配和归约。


一、Stream创建及注意事项

  • Stream只能操作一次
  • Stream方法返回的是新的流
  • Stream不调用终结方法,中间的操作不会执行
package stream;

import java.util.*;
import java.util.stream.Stream;

/**
 * Stream创建和注意事项
 *
 * @author dd
 * @since 2021/12/30
 */
public class StreamGetAndNotice 
    /**
     * Stream创建方法
     */
    public void testGet() 
        // 方式1 : 根据Collection获取流
        // Collection接口中有一个默认的方法: default Stream<E> stream()
        List<String> list = new ArrayList<>();
        Stream<String> stream1 = list.stream();

        Set<String> set = new HashSet<>();
        Stream<String> stream2 = set.stream();

        Map<String, String> map = new HashMap<>();
        Stream<String> stream3 = map.keySet().stream();
        Stream<String> stream4 = map.values().stream();
        Stream<Map.Entry<String, String>> stream5 = map.entrySet().stream();

        // 方式2 : Stream中的静态方法of获取流
        // static<T> Stream<T> of(T... values)
        Stream<String> stream6 = Stream.of("aa", "bb", "cc");

        String[] strs = "aa", "bb", "cc";
        Stream<String> stream7 = Stream.of(strs);

        // 基本数据类型的数组行不行?不行的,会将整个数组看做一个元素进行操作.
        int[] arr = 11, 22, 33;
        Stream<int[]> stream8 = Stream.of(arr);
    

    /**
     * 注意事项样例
     */
    public void notice() 
        Stream<String> stream = Stream.of("aa", "bb", "cc");
        // 1. Stream只能操作一次
        // long count = stream.count();
        // long count2 = stream.count();

        // 2. Stream方法返回的是新的流
        // Stream<String> limit = stream.limit(1);
        // System.out.println("stream" + stream);
        // System.out.println("limit" + limit);

        // 3. Stream不调用终结方法,中间的操作不会执行
        stream.filter((s) -> 
            System.out.println(s);
            return true;
        ).count();
    



二、Stream常用处理方法

package stream;

import stream.entity.Person;

import java.util.Optional;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * Stream常用方法
 * @author dd
 * @since 2021/12/30
 */
public class StreamCommonFunc 
    Stream<String> stream = Stream.of("1111", "222", "333", "44", "55", "55");

    /**
     * 循环
     */
    public void testForeach() 
        stream.forEach(System.out::println);
    

    /**
     * 获取数量
     */
    public void testCount() 
        System.out.println(stream.count());
    

    /**
     * 得到名字长度为3个字的人(过滤)
     */
    public void testFilter() 
        stream.filter(s -> s.length() == 3).forEach(System.out::println);
    

    /**
     * 获取前3个数据
     */
    public void testLimit() 
        stream.limit(3).forEach(System.out::println);
    

    /**
     * 跳过前两个数据
     */
    public void testSkip() 
        stream.skip(3).forEach(System.out::println);
    

    /**
     * 映射
     */
    public void testMap() 
        Stream<Integer> s = stream.map(Integer::parseInt);
        s.forEach(System.out::println);
    

    /**
     * 排序
     */
    public void testSorted() 
        Stream<Integer> s = stream.map(Integer::parseInt);
        s.sorted((i1, i2) -> i2 - i1).forEach(System.out::println);
    

    /**
     * 去重
     */

    public void testDistinct() 
        stream.distinct().forEach(System.out::println);
    

    /**
     * 条件匹配
     */
    public void testMatch() 
        System.out.println(stream.allMatch(s -> s.length() > 2));
        System.out.println(stream.anyMatch(s -> s.length() > 2));
        System.out.println(stream.noneMatch(s -> s.length() > 2));
    

    /**
     * 查找第一个元素
     */
    public void testFind() 
        System.out.println(stream.findFirst().get());
    

    /**
     * 获取最大最小值
     */
    public void testMax_Min() 
        // 获取最大值
        // 1, 3, 5, 6
        Optional<Integer> max = Stream.of(5, 3, 6, 1).max((o1, o2) -> o1 - o2);
        System.out.println("最大值: " + max.get());

        // 获取最小值
        // 1, 3, 5, 6
        Optional<Integer> min = Stream.of(5, 3, 6, 1).min((o1, o2) -> o1 - o2);
        System.out.println("最小值: " + min.get());
    


    public void testReduce() 
        // T reduce(T identity, BinaryOperator<T> accumulator);
        // T identity: 默认值
        // BinaryOperator<T> accumulator: 对数据进行处理的方式
        // reduce如何执行?
        // 第一次, 将默认值赋值给x, 取出集合第一元素赋值给y
        // 第二次, 将上一次返回的结果赋值x, 取出集合第二元素赋值给y
        // 第三次, 将上一次返回的结果赋值x, 取出集合第三元素赋值给y
        // 第四次, 将上一次返回的结果赋值x, 取出集合第四元素赋值给y
        int reduce = Stream.of(4, 5, 3, 9).reduce(0, (x, y) -> 
            System.out.println("x = " + x + ", y = " + y);
            return x + y;
        );
        System.out.println("reduce = " + reduce); // 21

        // 获取最大值
        Integer max = Stream.of(4, 5, 3, 9).reduce(0, (x, y) -> 
            return x > y ? x : y;
        );
        System.out.println("max = " + max);
    

    public void testMapReduce() 
        // 求出所有年龄的总和
        // 1.得到所有的年龄
        // 2.让年龄相加
        Integer totalAge = Stream.of(
                        new Person("刘德华", 58),
                        new Person("张学友", 56),
                        new Person("郭富城", 54),
                        new Person("黎明", 52))
                .map((p) -> p.getAge()).reduce(0, Integer::sum);

        System.out.println("totalAge = " + totalAge);


        // 找出最大年龄
        // 1.得到所有的年龄
        // 2.获取最大的年龄
        Integer maxAge = Stream.of(
                        new Person("刘德华", 58),
                        new Person("张学友", 56),
                        new Person("郭富城", 54),
                        new Person("黎明", 52))
                .map(p -> p.getAge())
                .reduce(0, Math::max);
        System.out.println("maxAge = " + maxAge);

        // 统计 a 出现的次数
        //                          1    0     0    1    0    1
        Integer count = Stream.of("a", "c", "b", "a", "b", "a")
                .map(s -> 
                    if (s == "a") 
                        return 1;
                     else 
                        return 0;
                    
                )
                .reduce(0, Integer::sum);
        System.out.println("count = " + count);
    

    public void testNumericStream() 
        // Integer占用的内存比int多,在Stream流操作中会自动装箱和拆箱
        Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);
        // 把大于3的打印出来
        // stream.filter(n -> n > 3).forEach(System.out::println);

        // IntStream mapToInt(ToIntFunction<? super T> mapper);
        // IntStream: 内部操作的是int类型的数据,就可以节省内存,减少自动装箱和拆箱

        IntStream intStream = Stream.of(1, 2, 3, 4, 5).mapToInt(Integer::intValue);
        intStream.filter(n -> n > 3).forEach(System.out::println);
    

    /**
     * stream连接
     */
    public void testContact() 
        Stream<String> streamA = Stream.of("张三");
        Stream<String> streamB = Stream.of("李四");

        // 合并成一个流
        Stream<String> newStream = Stream.concat(streamA, streamB);
        // 注意:合并流之后,不能操作之前的流啦.
        // streamA.forEach(System.out::println);

        newStream.forEach(System.out::println);
    



三、并行Stream流创建及使用

package com.cloud.jdk8.stream;

import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * 并行Stream流创建及使用
 * @author dd
 * @since 2021/12/31
 */
public class StreamParallel 

    /**
     * 并行Stream流创建方法
     */
    @Test
    public void testGetParallelStream() 
        // 掌握获取并行Stream流的两种方式
        // 方式一:直接获取并行的Stream流
        List<String> list = new ArrayList<>();
        Stream<String> stream = list.parallelStream();

        // 方式二:将串行流转成并行流
        Stream<String> parallel = list.stream().parallel();
    

    /**
     * 并行Stream流使用
     */
    @Test
    public void testParallel() 
        Stream.of(4, 5, 3, 9, 1, 2, 6)
                .parallel() // 转成并行流
                .filter(s -> 
                    System.out.println(Thread.currentThread() + "::" + s);
                    return s > 3;
                )
                .count();
    

    /**
     * parallelStream线程安全问题
     */
    @Test
    public void parallelStreamNotice() 
        ArrayList<Integer> list = new ArrayList<>();
        /*IntStream.rangeClosed(1, 1000)
                .parallel()
                .forEach(i -> 
                    list.add(i);
                );
        System.out.println("list = " + list.size());*/

        // 解决parallelStream线程安全问题方案一: 使用同步代码块
        /*Object obj = new Object();
        IntStream.rangeClosed(1, 1000)
                .parallel()
                .forEach(i -> 
                    synchronized (obj) 
                        list.add(i);
                    
                );*/

        // 解决parallelStream线程安全问题方案二: 使用线程安全的集合
        // Vector<Integer> v = new Vector();
        /*List<Integer> synchronizedList = Collections.synchronizedList(list);
        IntStream.rangeClosed(1, 1000)
                .parallel()
                .forEach(i -> 
                    synchronizedList.add(i);
                );
        System.out.println("list = " + synchronizedList.size());*/

        // 解决parallelStream线程安全问题方案三: 调用Stream流的collect/toArray
        List<Integer> collect = IntStream.rangeClosed(1, 1000)
                .parallel()
                .boxed()
                .collect(

以上是关于jdk8新特性-Stream流详解及使用样例(Stream创建使用收集并行流注意事项)的主要内容,如果未能解决你的问题,请参考以下文章

jdk8新特性-Stream流详解及使用样例(Stream创建使用收集并行流注意事项)

java8新特性Stream流操作详解及实战3

java8新特性Stream流操作详解及实战3

java8新特性Stream流操作详解及实战3

Jdk8新特性之Stream

高效开发:jdk8新特性,流模式