Java8 Stream 的最佳实践
Java8 Stream 的最佳实践
java8stream提供了对于集合类的流失处理,其具有以下特点:
Lazy Evaluation(长度可以无限)
只能使用一次
内部迭代
Lazy Evaluation类似函数式中的LazyList,只有在需要时才去求值。减少了内存消耗,Java中可以用Iterator模拟。只有在进行终端操作时,stream才会执行。但是这个延迟计算不能保证流中的某个值单独延迟,需要时单独分配资源。
内部迭代的意思是我们告诉程序要实现的功能,迭代由程序自己控制。如filter时,我们只提供Predicate,而不是自己写for循环,至于程序自己是如何实现过滤数据的,我们并不关心。可能随着stream类库的迭代,实现效率会逐步提升。PS:新版本的Java类库String终于可以直接拼串了 ,而且性能很好。
使用Stream的原则:
可读性、bugfree、短
Do
- 开发过程中最常用的Stream实现就是filter map reduce/collect操作,这种处理可以替代很大部分的(至少50%)的for循环。
// 读入数据,笔试用
Scanner sc = new Scanner(System.in);
String ss = sc.nextLine();
int[] nums = Arrays.stream(ss.split("\\s")).mapToInt(Integer::valueOf).toArray();
// flatMap只使用一次
// 这个例子来自于On Java 8
// 字符串打散,注意不要打散成char
// 常见的模式(方法返回流)
public static Stream<String> stream(String filePath) throws Exception {
return Files.lines(Paths.get(filePath))
.skip(1) // First (comment) line
.flatMap(line ->
Pattern.compile("\\W+").splitAsStream(line));
}
// 一对多关系,保存到数据库,命令式编程需要两层for循环
List<Role> roles = users.stream().flatMap(user -> user.getRoles().stream()).collect(toList());
saveBatch(roles);
// 生成随机数组
int[] nums = new Random().ints(0, 100).limit(10).toArray();
// optional流的处理
stream1.filter(Optional::isPresent).map(Optional::get).collect(toList());
stream2.map(opt -> opt.orElse(defaultValue)).collect(toList());
// forEach
stream3.forEach(System.out::println);
// 生成Map,这种最终操作我后面会发文章详细分析Collectors工具类
Map<Long, User> idToUserMap = users.stream().collect(toMap(User::getId, it -> it));
// 获取角色到用户的映射(一对多)
HashMultiMap<Long, User> roleIdToUsersMap = userVos.stream().collect(toMultiMap(UserVo::getRoleId, UserVo::getUser, HashMultimap::create));
// 分组
Map<Integer, List<User>> usersByLevelMap = users.collect(groupingBy(User::getLevel));
// 字符串拼接
subscriptions.stream().map(Object::toString).collect(joining(",", "(", ")"));
// 参数校验
boolean validated = request.getResources().stream().allMatch(authorities::contains);
if (!validated) throw ...
IntStream::sum, max, min, average, count...
// 教学意义
质数流,完全数流...
- 开发中的大部分时候我们不需要特别在意性能,仅在需要时优化。
比如你需要一个字符串匹配算法,需要自己实现一些特殊功能,先写出暴力匹配,之后再优化。
比如我想获取一个前十名的排行榜,我不必在自己编写优先队列,或者使用其他类库。当需要优化时,再考虑优化。
// 至少我们可以确定:使用stream的内部迭代中时间复杂度最多是nlogn。
Comparator<User> compScore = Comparator.comparingDouble(User::getScore).reversed();
List<User> top10 = users.stream().sorted(compScore).limit(10).collect(toList());
Don’t
毕竟Java不是纯函数式的语言,还要前向兼容,所以只能部分利用函数式的思想。以下这些做法在开发中应该避免。
- 忽略空指针。对于可能存在空指针的类直接使用Stream,特别是类中具有复杂的引用关系时,比如我通过Feign获取的对象。即使使用Optional,也会令可读性大大下降。
- 包含复杂的异常处理。异常处理时不要使用stream,stream天生和异常相冲突,函数式编程中异常也是一类副作用,两种很难相容。Java也没有Either类。尽量少用,非要用可以使用Optional或者 try-catch 包装,
- 使用stream类中的flatMap实现多重循环。这样可读性很差。就想try-catch嵌套一样难受。英文里叫boilerplate,不知道中文用哪个词,大意就是跟八股文一样繁杂。
- 使用forEach。尽量不要使用forEach,forEach只限定在几种特定的编程模式。这个方法很难调试。
- 在代码面试或笔试中使用。因为人家面试官考的就是你对命令式编程的理解、算法与数据结构、函数内部状态的追踪,而且代码笔试中特别看重性能,stream会生成很多不可变的中间变量,占用空间,在在线编程环境上性能不稳定。
- 使用parallel方法。这个方法对于性能的提升有限,只有在进行大量计算时有用。几乎用不到。
Java8 Stream 的最佳实践的更多相关文章
- 对Java8 stream的简单实践
最近学习很多Java8方面的新特性,特地做了一些简单的实践和总结. import java.util.*; import java.util.stream.Collectors; public cla ...
- 5万字长文:Stream和Lambda表达式最佳实践-附PDF下载
目录 1. Streams简介 1.1 创建Stream 1.2 Streams多线程 1.3 Stream的基本操作 Matching Filtering Mapping FlatMap Reduc ...
- Spring Batch在大型企业中的最佳实践
在大型企业中,由于业务复杂.数据量大.数据格式不同.数据交互格式繁杂,并非所有的操作都能通过交互界面进行处理.而有一些操作需要定期读取大批量的数据,然后进行一系列的后续处理.这样的过程就是" ...
- java 读取文件最佳实践
1. 前言 Java应用中很常见的一个问题,如何读取jar/war包内和所在路径的配置文件,不同的人根据不同的实践总结出了不同的方案,但其他人应用却会因为环境等的差异发现各种问题,本文则从原理上解释 ...
- 转载--JAVA读取文件最佳实践
1. 前言 Java应用中很常见的一个问题,如何读取jar/war包内和所在路径的配置文件,不同的人根据不同的实践总结出了不同的方案,但其他人应用却会因为环境等的差异发现各种问题,本文则从原理上解释 ...
- [转]Android开发最佳实践
——欢迎转载,请注明出处 http://blog.csdn.net/asce1885 ,未经本人同意请勿用于商业用途,谢谢—— 原文链接:https://github.com/futurice/and ...
- Atitit. 软件设计 模式 变量 方法 命名最佳实践 vp820 attilax总结命名表大全
Atitit. 软件设计 模式 变量 方法 命名最佳实践 vp820 attilax总结命名表大全 1. #====提升抽象层次1 2. #----使用通用单词1 3. #===使用术语..1 4. ...
- 10个精妙的Java编码最佳实践
这是一个比Josh Bloch的Effective Java规则更精妙的10条Java编码实践的列表.和Josh Bloch的列表容易学习并且关注日常情况相比,这个列表将包含涉及API/SPI设计中不 ...
- spring-boot-2.0.3之quartz集成,最佳实践
前言 开心一刻 快过年了,大街上,爷爷在给孙子示范摔炮怎么放,嘴里还不停念叨:要像这样,用劲甩才能响.示范了一个,两个,三个... 孙子终于忍不住了,抱着爷爷的腿哭起来:爷呀,你给我剩个吧! 新的一年 ...
随机推荐
- [操作系统]LINUX进程状态说明
R(task_running) : 可执行状态 只有在该状态的进程才可能在CPU上运行.而同一时刻可能有多个进程 处于可执行状态,这些进程的task_struct结构(进程控制块)被放入对应CPU的 ...
- CSS预编译器
零.CSS预编译器 CSS预处理器是指对生成CSS前的某一语法的处理.CSS预处理器用一种专门的编程语言,进行Web页面样式设计,然后再编译成正常的CSS文件,供项目使用 CSS预处理器为CSS增加一 ...
- [总结] 零散的 tricks
对于类似构造方案的题目,先确定其中一些关键位置的方案,然后看是否能较为简单地推出其他位置的方案. 一个长度为 \(n\) 的序列,满足 \[a_1\le-a_4\le a_7\le-a_{10}\le ...
- 绕过 Docker ,大规模杀死容器
关注「开源Linux」,选择"设为星标" 回复「学习」,有我为您特别筛选的学习资料~ 作者 | Connor Brewster 译者 | Sambodhi 策划 | Tina 要让 ...
- 太极限了,JDK的这个BUG都能被我踩到
hello,大家好呀,我是小楼. 之前遇到个文件监听变更的问题,刚好这周末有空研究了一番,整理出来分享给大家. 从一次故障说起 我们还是从故障说起,这样更加贴近实际,也能让大家更快速理解背景. 有一个 ...
- kNN-预测
现在进行第五步,对数据进行预测 那么要做的的是从数据集里面拿出一部分作为要预测的,剩下的去比较,书上使用的是10% # 对之前做好的kNN算法进行预测 # 首先获取之前构造好的kNN分类器.数据.规则 ...
- Redis集群高频问答,连夜肝出来了
Redis 集群方案 Redis集群方案应该怎么做?都有哪些方案? 使用codis方案:目前用的多的集群方案,基本和twemproxy一致的效果,但它支持在节点数量改变情况下,旧节点数据可恢复到新h ...
- linux篇-新建svn仓库
1昨天需要在服务器上新建一个仓库,解决方法是把已有的仓库拷贝出来,库删除在放进去 2然后今天想看看有没有命令的方法 find / -name project 首先查看一下项目的位置 3创建仓库 svn ...
- 好客租房13-在jsx中使用javascript表达式
嵌入js表达式 数据存储在js中 语法{javascript表达式} 注意语法中是单大括号 不是双大括号 //导入react import React from "react&quo ...
- OpenHarmony3.1 Release版本特性解析——硬件资源池化架构介绍
李刚 OpenHarmony 分布式硬件管理 SIG 成员 华为技术有限公司分布式硬件专家 OpenHarmony 作为面向全场景.全连接.全智能时代的分布式操作系统,通过将各类不同终端设备的能力进行 ...