Java之stream流浅析

Source

Stream流是Java8中提供的一个重要新特性,它允许开发人员以声明方式处理集合。其中parallelStream其实就是一个并行执行的流,它通过默认的ForkJoinPool,可能提高你的多线程任务的速度。
Stream流特点如下

  • stream不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果;
  • stream不会改变数据源,通常情况下会产生一个新的集合;
  • stream具有延迟执行特性,只有调用终端操作时,中间操作才会执行;
  • stream不可复用,对一个已经进行了终端操作的流再次调用会抛出异常;

Stream流接口中定义了许多对于集合的操作方法,主要分为两类:中间操作和终端操作。
在这里插入图片描述

  • 中间操作:返回一个流,通过这种方式可以将多个中间操作连接起来,形成一个调用链,从而转换为另一个流。除非调用链后存在一个终端操作,否则中间操作对流不会进行任何结果处理。
  • 终端操作:返回一个具体的结果,如list等。

常见的中间操作方法有:limit、skip、distinct、sorted等。
常见的终端操作方法有:forEach、count、toArray、reduce等。
常见的收集操作方法有:collect。
使用Stream流的方式操作完毕后,通过收集方法collect将数据收集到集合中,工具类Collectors提供了具体的收集方式,如下

  • toList:把元素收集到List集合中;
  • toSet:把元素收集到Set集合中;
  • toMap:把元素收集到Map集合中;

Stream性能

  • 在少数据量场景(size<1000)
    stream流的foreach处理效率不如iterator迭代的效率,但实际上这些处理任务本身运行实际都低于毫秒,这点效率的差距对普通业务几乎没有影响,而stream流却可以使得代码更简单优雅;
  • 在多数据量场景(size>10000)
    stream流的foreach处理效率高于iterator迭代的效率,特别是使用了并行流,在cpu恰好将线程分配到多个核心的条件下,效率很高。
  • parallelStream并行流
    parallelStream受cpu环境影响很大,当没分配到多个cpu核心时,加上引入了forkJoinPool的开销,运行效率还不如stream流。

下面分别对for循环、foreach循环、stream.foreach循环、parallelStream.foreach循环的性能进行测试

public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>();
        for (int i = 0; i < 1000; i++) {
            list.add(i);
        }
        Long startTime = System.currentTimeMillis();
        forMethod(list);
        Long endTime = System.currentTimeMillis();
        System.out.println("result:" + (endTime - startTime));//29 15 31 15 16
    }

    private static void forMethod(List<Integer> list) {
        for (Integer i : list) {
            System.out.println("------" + i);
        }
    }
public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>();
        for (int i = 0; i < 1000; i++) {
            list.add(i);
        }
        Long startTime = System.currentTimeMillis();
        foreachMethod(list);
        Long endTime = System.currentTimeMillis();
        System.out.println("result:" + (endTime - startTime));//85 80 84 84 85
    }

    private static void foreachMethod(List<Integer> list) {
        list.forEach(integer -> {
            System.out.println("------" + integer);
        });
    }
public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>();
        for (int i = 0; i < 1000; i++) {
            list.add(i);
        }
        Long startTime = System.currentTimeMillis();
        streamMethod(list);
        Long endTime = System.currentTimeMillis();
        System.out.println("result:" + (endTime - startTime));//116 115 85 84 84
    }

    private static void streamMethod(List<Integer> list) {
        list.stream().forEach(integer -> {
            System.out.println("------" + integer);
        });
    }
public static void main(String[] args) {
        List<Integer> list = new ArrayList<Integer>();
        for (int i = 0; i < 1000; i++) {
            list.add(i);
        }
        Long startTime = System.currentTimeMillis();
        parallelStreamMethod(list);
        Long endTime = System.currentTimeMillis();
        System.out.println("result:" + (endTime - startTime)); //179 138 140 122 175
    }

    private static void parallelStreamMethod(List<Integer> list) {
        list.parallelStream().forEach(integer -> {
            System.out.println("------" + integer);
        });
    }

在数据量为1000时,效率依次是for>foreach>stream.foreach>parallelStream.foreach。
理论上,数据量越大,stream的效率越高,parallelStream的效率会最高且是并行处理。但选用需思考其场景,避免数据安全问题。