Java 8之Stream适用场景

Stream是Java 8中的一个大的改进。Stream的功能是,支持集合的各种操作,比如filter, sum, max, min, average, map, reduce等等。所以我个人认为Stream的出现是基于以下原因:

  • 增强集合操作
  • 拥抱函数式编程
  • 充分利用Lambda
  • 执行效率的提高 - 透明支持多线程集合操作

笔者尝试测试一下Stream并发处理的威力,发现面对特别简单的任务,Stream并发处理相较于传统的for each循环,执行效率没有优势。看起来Stream不是免费的午餐,创建Stream还是要一些开销的。所以这促使笔者思考该在什么场景下才使用Stream。

测试例子

笔者测试两个例子,一个任务非常简单,另外一个稍微复杂一点。从结果看起来,并行Stream总是比串行快,任务简单的情况,For Loop更快,任务复杂一点,并行Stream后来居上,并行带来的改进足以cover创建Stream的开销。

测试的小工具类

public class TimeRecorder {
    private long startTime;
    private long endTime;

    public void start() {
        startTime = System.currentTimeMillis();
    }

    public long end() {
        endTime = System.currentTimeMillis();
        return endTime - startTime;
    }

    public long getDuration() {
        return endTime - startTime;
    }

}

任务非常简单的例子

只调用intValue这么一个小方法。

public class StreamDemoSimple {
    public static void main(String[] args) {
        List<Integer> intList = new LinkedList<Integer>();
        for (int i = 1; i <= 1000000; i++) {
            intList.add(i);
        }

        TimeRecorder recorder = new TimeRecorder();

        recorder.start();
        intList.stream().forEach(i -> {
            i.intValue();
        });
        recorder.end();
        System.out.print("Stream iterator:");
        System.out.println(recorder.getDuration());

        recorder.start();
        intList.parallelStream().forEach(i -> {
            i.intValue();
        });
        recorder.end();
        System.out.print("Parallel Stream iterator:");
        System.out.println(recorder.getDuration());

        recorder.start();
        for (Integer i : intList) {
            i.intValue();
        }
        recorder.end();
        System.out.print("Normal iterator:");
        System.out.println(recorder.getDuration());
    }
}

输出如下:

Stream iterator:447

Parallel Stream iterator:142

Normal iterator:70

任务稍微复杂的例子

多执行了几步而已。

public class StreamDemo {
    public static void main(String[] args) {
        List<Integer> intList = new LinkedList<Integer>();
        for (int i = 1; i <= 1000000; i++) {
            intList.add(i);
        }

        TimeRecorder recorder = new TimeRecorder();

        recorder.start();
        intList.stream().forEach(i -> {
            i.intValue();
            i.intValue();
            i.toString();

            i.intValue();
            i.intValue();
            i.toString();
        });
        recorder.end();
        System.out.print("Stream iterator:");
        System.out.println(recorder.getDuration());

        recorder.start();
        intList.parallelStream().forEach(i -> {
            i.intValue();
            i.intValue();
            i.toString();

            i.intValue();
            i.intValue();
            i.toString();
        });
        recorder.end();
        System.out.print("Parallel Stream iterator:");
        System.out.println(recorder.getDuration());

        recorder.start();
        for (Integer i : intList) {
            i.intValue();
            i.intValue();
            i.toString();

            i.intValue();
            i.intValue();
            i.toString();
        }
        recorder.end();
        System.out.print("Normal iterator:");
        System.out.println(recorder.getDuration());
    }
}

输出如下:

Stream iterator:808

Parallel Stream iterator:313

Normal iterator:377

Stream的适合场景

  • 集合操作超过两个步骤

    比如先filter再for each

    这时Stream显得优雅简洁,效率也高

  • 任务较重,注重效能,希望并发执行

    很容易的就隐式利用了多线程技术。非常好的使用时机。

  • 函数式编程的编码风格里

    Stream的设计初衷之一

结语

Lambda,Stream等等新特性使得Java函数式编程更为自然。合适的环境下非常值得合理使用。但是请记住Stream的创建以及传输也有损耗,特别简单的场景可能传统的For Loop更为适合。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-05 08:42:25

Java 8之Stream适用场景的相关文章

挨踢部落坐诊第四期:Java消息队列的应用场景和作用

挨踢部落是为核心开发者提供深度技术交流,解决开发需求,资源共享的服务社群.基于此社群,我们邀请了业界技术大咖对开发需求进行一对一突破,解除开发过程中的绊脚石.以最专业.最高效的答复为开发者解决开发难题. 消息队列 话题关键词:消息队列.索引.App.路由.接口 部落阵容:51CTO管理团队: 面向对象:移动开发者.IT运维.数据分析师 参与方式:加入51CTO开发者QQ交流群(群号370892523(已满).请加312724475),有任何技术问题,在群里提问,或发给群主小官. 活动详情: 重庆

详解Java 8中Stream类型的“懒”操作

在进入正题之前,我们需要先引入Java 8中Stream类型的两个很重要的操作: 中间和终结操作(Intermediate and Terminal Operation) Stream类型有两种类型的方法: 中间操作(Intermediate Operation) 终结操作(Terminal Operation) 官方文档给出的描述为[不想看字母的请直接跳过]: Stream operations are divided into intermediate and terminal operat

Java基础(十一) Stream I/O and Files

Java基础(十一) Stream I/O and Files 1. 流的概念 程序的主要任务是操纵数据.在Java中,把一组有序的数据序列称为流.根据操作的方向,可以把流分为输入流和输出流两种.程序从输入流读取数据,向输出流写出数据. 文件 输入流 输出流 文件 内存 -------------> Java程序 ------------------> 内存 键盘 控制台 | | 数据源 数据目的地 Java I/O系统负责处理程序的输入和输出,I/O类库位于java.io包中,它对各种常见的

java.io.IOException: Stream closed 异常的原因和处理

java.io.IOException: Stream closed 多个线程索引同一个input  stream,当某一个thread在执行完之后,把这个inputstream关闭了:而此时正在从这个input  stream流中读取信息的线程就会抛出  java.io.IOException:  Stream  closed  异常. 终于找到这个异常的根源所在,原来是两个页面同时调用一个jsp,这个jsp中的内建对象out在执行out.close()时发生的异常,也就是当某一个thread

Java 常用List集合使用场景分析

Java 常用List集合使用场景分析 过年前的最后一篇,本章通过介绍ArrayList,LinkedList,Vector,CopyOnWriteArrayList 底层实现原理和四个集合的区别.让你清楚明白,为什么工作中会常用ArrayList和CopyOnWriteArrayList?了解底层实现原理,我们可以学习到很多代码设计的思路,开阔自己的思维.本章通俗易懂,还在等什么,快来学习吧! 知识图解: 技术:ArrayList,LinkedList,Vector,CopyOnWriteAr

Java导出Excel,java.io.IOException: Stream is already closed

使用POI进行Excel导出的时候,后台报了这样一个错误: java.io.IOException: Stream is already closed 导出的代码如下: 查了半天,才发现问题出在第409行 out.close(); out这个输出流是不用自己手动关闭的,系统会自动替我们关闭,自己手动关闭的话还会引发问题. 实际上只有像下面这种使用new关键字创建的输入/输出流,才需要自己手动关闭 InputStream input = new FileInputStream(new File("

java中的Stream流

java中的Stream流 说到Stream便容易想到I/O Stream,而实际上,谁规定"流"就一定是"IO流"呢?在Java 8中,得益于Lambda所带 来的函数式编程,引入了一个全新的Stream概念,用于解决已有集合类库既有的弊端. 一.引言 传统集合的多步遍历代码 几乎所有的集合(如 Collection 接口或 Map 接口等)都支持直接或间接的遍历操作.而当我们需要对集合中的元 素进行操作的时候,除了必需的添加.删除.获取外,典型的就是集合遍历.

Java 中需要编码的场景

I/O 操作中存在的编码 我们知道涉及到编码的地方一般都在字符到字节或者字节到字符的转换上,而需要这种转换的场景主要是在 I/O 的时候,这个 I/O 包括磁盘 I/O 和网络 I/O,关于网络 I/O 部分在后面将主要以 Web 应用为例介绍.下图是 Java 中处理 I/O 问题的接口: Reader 类是 Java 的 I/O 中读字符的父类,而 InputStream 类是读字节的父类,InputStreamReader 类就是关联字节到字符的桥梁,它负责在 I/O 过程中处理读取字节到

Java中需要编码的场景

一.I/O 操作中存在的编码 涉及到编码的地方一般都在字符到字节或者字节到字符的转换上,而需要这种转换的场景主要是在 I/O 的时候,这个 I/O 包括磁盘 I/O 和网络 I/O,关于网络 I/O 部分在后面将主要以 Web 应用为例介绍. 下图是 Java 中处理 I/O 问题的接口:       Reader 类是 Java 的 I/O 中读字符的父类,而 InputStream 类是读字节的父类,InputStreamReader 类就是关联字节到字符的桥梁,它负责在 I/O 过程中处理