最近项目里有这么一段代码,我在做 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. Portal简介

    Portal 在英语中是入口的意思.Portal 认证通常也称为 Web 认证,一般将 Portal 认 证网站称为门户网站. 未认证用户上网时,设备强制用户登录到特定站点,用户可以免费访问其中的服务 ...

  2. python linecache模块读取文件用法详解

    linecache模块允许从任何文件里得到任何的行,并且使用缓存进行优化,常见的情况是从单个文件读取多行. linecache.getlines(filename) 从名为filename的文件中得到 ...

  3. 二、C到C++的升级

    C++ 的加强主要表现在:类型的加强.面向对象支持 1.C++改进 C++更强调语言的实用性,所有的变量都可以再需要使用的时候再定义,C语言中的变量都必须在作用域开始的位置定义 int c = 0; ...

  4. RSA等非对称加密为什么要用公钥加密,而用私钥解密?

    1.RSA是不对称加密算法,它的公钥可能会被多人持有(公钥公钥,公开的密钥),而私钥只有一人拥有,例如支付宝开放平台,私钥只有支付宝公司持有,而公钥则是所有接入它API的公司都能得到.对于公钥加密的信 ...

  5. 3 个用于数据科学的顶级 Python 库

    使用这些库把 Python 变成一个科学数据分析和建模工具. Python 的许多特性,比如开发效率.代码可读性.速度等使之成为了数据科学爱好者的首选编程语言.对于想要升级应用程序功能的数据科学家和机 ...

  6. HTML5页面元素中的文本最快速替换replace()方法

    $.ajax({ type:"get", url:spanUrl, dataType:'jsonp', jsonpCallback:'jsonp',//jsonp数据,需要数据库提 ...

  7. 5458. 【NOIP2017提高A组冲刺11.7】质数

    5458. [NOIP2017提高A组冲刺11.7]质数 (File IO): input:prime.in output:prime.out Time Limits: 1000 ms  Memory ...

  8. 精通SpringBoot--整合druid监控SQL执行

    咳咳,今天我们做些简单而实用的东西,使用springboot 整合alibaba的driud数据库监控工具.alibaba已经提供了spring-boot-starter的jar包了.先看pom.xm ...

  9. UVA - 10213 How Many Pieces of Land?(欧拉公式 + 高精度)

    圆上有n个点,位置不确定.问这些点两两连接成的线段,最多可以把圆划分成多少块平面? 欧拉公式:V-E+F = 2,V是点数,E是边数,F是面数. 答案是F=C(n,4)+C(n,2)+1,看的别人推的 ...

  10. Leetcode 105. 从前序与中序遍历序列构造二叉树

    题目链接 题目描述 根据一棵树的前序遍历与中序遍历构造二叉树. 注意: 你可以假设树中没有重复的元素. 例如,给出 前序遍历 preorder = [3,9,20,15,7] 中序遍历 inorder ...