项目记事【StreamAPI】:使用 StreamAPI 简化对 Collection 的操作
最近项目里有这么一段代码,我在做 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 的操作的更多相关文章
- java8-StreamAPI之collection归约操作
一说明 经过前一篇的StreamAPI学习,基本的流操作我相信大家都熟练于心了,那么今天是要详细解析一下收集器(collect)这么API 前提要区分,collect(StreamAPI)与coll ...
- 使用元数据简化jdbc代码---查询操作(用到反射)
使用元数据简化jdbc代码---查询操作(用到反射) 一 思路分析 简化就是把共同的地方提取出来并放到一个方法里,在用到时只要调用就ok了,上一篇介绍了更新的操作,而查询的操作相对来说比较复杂,因为 ...
- IDEA项目搭建七——使用Feign简化消费者端操作
一.简介 我们可以看到上一篇文章的消费者这边调用Service时比较麻烦,所以我们可以使用Feign来简化这部分操作,它底层也是使用Ribbon实现的只是Ribbon支持HTTP和TCP两种通信协议, ...
- IDEA项目搭建八——使用MybatisPlus简化数据库交互
一.MybatisPlus简化数据库交互 我们使用Mybatis发现需要在mapper.xml中写很多重复的简单CRUD(增删改查),使用MybatisPlus可以大大简化这部分代码,官方文档http ...
- 基于已构建S2SH项目配置全注解方式简化配置文件
如果还不熟悉s2sh项目搭建的朋友可以先阅读 eclipse环境下基于tomcat-7.0.82构建struts2项目 eclipse环境下基于已构建struts2项目整合spring+hiberna ...
- 项目记事【SpringMVC-1】:后台接收前端传来的JSON,并转成对象
背景: 最近项目中使用SpringMVC,需要从前端接收JSON格式的请求,在后端自动转成一个与JSON格式相同的对象. 由于是一个老项目,Spring的版本是3.2.7. 问题1:POST or G ...
- 项目记事【多线程】:关于 SimpledDateFormat 的多线程问题
背景: 最近项目引入了 SonarLink,解决代码规范的问题,在检查历史代码的时候,发现了一个问题. 先看代码: public class DateUtil { private static fin ...
- 项目记事【Hibernate-1】:调用 saveOrUpdate() 方法出错
Hibernate 版本:3.3.1 背景: 后端编辑一个对象,该对象(ProductDO)下,有一个另一个自定义对象(ProductLiabilityDO)的 OneToMany 关系,如下: @O ...
- 项目记事【SpringMVC-2】:将后台的对象,转成JSON报文
Spring版本:3.2.7 Jackson版本: <!--Jackson --> <dependency> <groupId>com.fasterxml.jack ...
随机推荐
- SummerVocation_Learning--java的线程机制
线程:是一个程序内部的执行路径.普通程序只有main()一条路径.如下列程序: import java.lang.Thread; //导入线程实现包 public class Test_Thread ...
- 散列表的ASL计算
题目: 已知关键字序列为{30,25,72,38,8,17,59},设散列表表长为15.散列函数是H(key)=key MOD 13,处理冲突的方法为二次探测法Hi= ( H(key) + di )m ...
- MySQL解决中文编码问题
转载组员博客 地址:MySQL解决中文编码问题
- JavaScript对象创建的九种方式
1.标准创建对象模式 var person = new Object(); person.name = "Nicholas"; person.age = 29; person.jo ...
- 802. Find Eventual Safe States
https://leetcode.com/problems/find-eventual-safe-states/description/ class Solution { public: vector ...
- unix gcc编译过程
gcc编译过程 现代编译器常见的编译过程: 源文件-->预处理-->编译/优化-->汇编-->链接-->可执行文件 对于gcc而言: 第一步 预处理 命令: ...
- 分数调查 HihoCoder - 1515
小Hi的学校总共有N名学生,编号1-N.学校刚刚进行了一场全校的古诗文水平测验. 学校没有公布测验的成绩,所以小Hi只能得到一些小道消息,例如X号同学的分数比Y号同学的分数高S分. 小Hi想知道利用这 ...
- Codeforces Round #461 (Div. 2) B. Magic Forest
B. Magic Forest time limit per test 1 second memory limit per test 256 megabytes Problem Description ...
- Flume-NG源码分析-整体结构及配置载入分析
在 http://flume.apache.org 上下载flume-1.6.0版本,将源码导入到Idea开发工具后如下图所示: 一.主要模块说明 flume-ng-channels 里面包含了fil ...
- Python虚拟机类机制之descriptor(三)
从slot到descriptor 在Python虚拟机类机制之填充tp_dict(二)这一章的末尾,我们介绍了slot,slot包含了很多关于一个操作的信息,但是很可惜,在tp_dict中,与__ge ...