最近项目里有这么一段代码,我在做 code-review 的时候,觉得可以使用 Java8 StreamAPI 简化一下。

这里先看一下代码(不是源码,一些敏感信息被我用其他类替代了):

    private static Set<String> doSomething1(String input) {
Set<String> target = new HashSet<>();
if (input != null) {
for (Pojo pojo : source) {
if (input.equals(pojo.getStr1())) {
target.add(pojo.getStr2());
}
}
}
return target;
}

其中 source 是一个 Set<Pojo> 的共享变量,Pojo 是自定义对象:

    private static class Pojo {
String str1;
String str2; Pojo(String str1, String str2) {
this.str1 = str1;
this.str2 = str2;
} public String getStr1() {
return str1;
} public String getStr2() {
return str2;
}
}

这个 doSomething1() 方法的功能很简单:

  • 声明一个新的 Set<String> 结构 target。
  • 遍历 source。
  • 将 input 依次与 source 中每个元素的 str1 属性进行比对。
  • 若比对成功,将元素的 str2 属性加入 target。
  • 遍历结束,返回 target。

从单纯的 Coding 角度而言,doSomething1() 方法实现得已经足够简便,但是使用 Java8 StreamAPI 可以仅仅使用一行代码的情况下完成这些操作。

仔细分析以上的操作,可以归纳为三个步骤:

  • 过滤数据 -> input.equals(pojo.getStr1()
  • 提取数据 -> pojo.getStr2()
  • 收集数据 -> target.add(pojo.getStr2())

这三个操作分别对应了 StreamAPI 的 filter,map,collect,因此可以简化成这样:

    private static Set<String> doSomething2(String input) {
return source.stream().filter(pojo -> input.equals(pojo.getStr1())).map(Pojo::getStr2).collect(Collectors.toSet());
}

功能测试

    private static Set<Pojo> source = new HashSet<>();

    public static void main(String[] args) {
prepareData();
for (String s : doSomething1("1")) {
System.out.println(s);
}
for (String s : doSomething2("1")) {
System.out.println(s);
}
} private static void prepareData() {
Pojo pojo1 = new Pojo("1", "2");
Pojo pojo2 = new Pojo("3", "4");
source.add(pojo1);
source.add(pojo2);
}

输出如下:

发现两者是等价的。

性能测试

一个应用程序的优秀与否,不在于代码的漂亮程度,而在于性能。

    public static void main(String[] args) {
prepareData(); long t3 = System.nanoTime();
doSomething2("123441");
long t4 = System.nanoTime();
printTime(t3, t4); long t1 = System.nanoTime();
doSomething1("123441");
long t2 = System.nanoTime();
printTime(t1, t2);
} private static void printTime(long t1, long t2) {
long t = t2 - t1;
double factor = Math.pow(10, 9);
System.out.println(t / factor);
} private static void prepareData() {
final int scale = 100000000;
Random r = new Random();
for (int i = 0; i < scale; ++i) {
String str1 = r.nextInt(scale) + "";
String str2 = r.nextInt(scale) + "";
source.add(new Pojo(str1, str2));
}
}

测试结果:

可以发现,使用 StreamAPI 大大降低了程序的效率,当数据量足够大的时候,这个比例会不断缩小。

我们可以这样理解:StreamAPI 针对的是相对大数据的操作,为一个数据量较小的 Collection 起一个 Stream 非常得不偿失,有种大炮打蚊子的感觉。

最后的内存溢出,是在 prepareData 的时候,和处理数据没有关系。

最后贴上大神的测试:Java8 Lambda表达式和流操作如何让你的代码变慢5倍

所以流操作,慎用!

项目记事【StreamAPI】:使用 StreamAPI 简化对 Collection 的操作的更多相关文章

  1. java8-StreamAPI之collection归约操作

    一说明 经过前一篇的StreamAPI学习,基本的流操作我相信大家都熟练于心了,那么今天是要详细解析一下收集器(collect)这么API 前提要区分,collect(StreamAPI)与coll ...

  2. 使用元数据简化jdbc代码---查询操作(用到反射)

    使用元数据简化jdbc代码---查询操作(用到反射) 一  思路分析 简化就是把共同的地方提取出来并放到一个方法里,在用到时只要调用就ok了,上一篇介绍了更新的操作,而查询的操作相对来说比较复杂,因为 ...

  3. IDEA项目搭建七——使用Feign简化消费者端操作

    一.简介 我们可以看到上一篇文章的消费者这边调用Service时比较麻烦,所以我们可以使用Feign来简化这部分操作,它底层也是使用Ribbon实现的只是Ribbon支持HTTP和TCP两种通信协议, ...

  4. IDEA项目搭建八——使用MybatisPlus简化数据库交互

    一.MybatisPlus简化数据库交互 我们使用Mybatis发现需要在mapper.xml中写很多重复的简单CRUD(增删改查),使用MybatisPlus可以大大简化这部分代码,官方文档http ...

  5. 基于已构建S2SH项目配置全注解方式简化配置文件

    如果还不熟悉s2sh项目搭建的朋友可以先阅读 eclipse环境下基于tomcat-7.0.82构建struts2项目 eclipse环境下基于已构建struts2项目整合spring+hiberna ...

  6. 项目记事【SpringMVC-1】:后台接收前端传来的JSON,并转成对象

    背景: 最近项目中使用SpringMVC,需要从前端接收JSON格式的请求,在后端自动转成一个与JSON格式相同的对象. 由于是一个老项目,Spring的版本是3.2.7. 问题1:POST or G ...

  7. 项目记事【多线程】:关于 SimpledDateFormat 的多线程问题

    背景: 最近项目引入了 SonarLink,解决代码规范的问题,在检查历史代码的时候,发现了一个问题. 先看代码: public class DateUtil { private static fin ...

  8. 项目记事【Hibernate-1】:调用 saveOrUpdate() 方法出错

    Hibernate 版本:3.3.1 背景: 后端编辑一个对象,该对象(ProductDO)下,有一个另一个自定义对象(ProductLiabilityDO)的 OneToMany 关系,如下: @O ...

  9. 项目记事【SpringMVC-2】:将后台的对象,转成JSON报文

    Spring版本:3.2.7 Jackson版本: <!--Jackson --> <dependency> <groupId>com.fasterxml.jack ...

随机推荐

  1. iOS开发学习之大牛们的博客

    http://blog.csdn.net/iosbird/article/details/51981023 唐巧:http://blog.devtang.com/blog/archives/ 王巍:h ...

  2. 【洛谷3648】[APIO2014] 序列分割(斜率优化DP)

    点此看题面 大致题意: 你可以对一个序列进行\(k\)次分割,每次得分为两个块元素和的乘积,求总得分的最大值. 区间\(DPor\)斜率优化\(DP\) 这题目第一眼看上去感觉很明显是区间\(DP\) ...

  3. VERITAS NETBACKUP运维手册(自制)

    ps:本文为目录.详情请点如下目录超链接 1 VERITAS NETBACKUP介绍 1.1 NBU基本概念 1.2 配置存储单元 1.3 配置备份策略(Policy) 1.4 配置NetBackup ...

  4. 数组 -----JavaScript

    本文摘要:http://www.liaoxuefeng.com/ JavaScript的Array可以包含任意数据类型,并通过索引来访问每个元素.(数据里面可以有多个不同类型的元素组成) 要取得Arr ...

  5. java: 非法字符: \65279

    IDEA导入项目后,编译的时候出现Error:(1, 1) java: 非法字符: \65279: 修改:找到编译报错的文件,用Notepad++工具,以UTF-8无BOM格式编码保存,然后重新编译即 ...

  6. Mac 系统 + Chrome浏览器 网页前端出现中文文字反转或顺序错乱

    问题背景 React开发的系统,收到一个BUG反馈,*"号个人统计"文字不正确,应为"个人号统计"*. 收到BUG后,打开浏览器查验是什么情况,难道犯了最基本的 ...

  7. 第22题:链表中倒数第k个结点

    题目描述 题目:输入一个链表,输出该链表中倒数第k个结点.为了符合大多数人的习惯,本题从1开始计数,即链表的尾结点是倒数第1个结点.例如一个链表有6个结点,从头结点开始它们的值依次是1.2.3.4.5 ...

  8. rsync常用命令和使用方法

    rsync是一个远程数据同步工具,可以实现数据的增量备份,这点比scp要好,scp只能全量备份.同步可以保持文件原有属性,传输过程加密,数据传输全. rsync 的传输模式有:        1. 本 ...

  9. linux下/dev/null被误删

    /dev/null文件是一个特殊的设备文件,可以用于清空一些日志文件,或者是使一些信息输出到此文件,用以节省硬盘空间.如果该空文件/dev/null文件被误删除掉, 如何再使用系统命令重新创建并设置该 ...

  10. python之斐波纳契数列

    斐波纳契数列 斐波那契数列指的是这样一个数列 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2584,4181,676 ...