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的效率会最高且是并行处理。但选用需思考其场景,避免数据安全问题。