[译]Java8:循环与函数式编程
Java8函数式编程的加入彻底改变了游戏规则。对Java开发者来说这是一个全新的世界,我们也需要做出相应的改变。
在这篇文章中我们将找寻传统循环代码的可替代方案。Java8的函数式编程特性改变了编程思路,从 “我们怎样去做” 变成了 “我们想做什么” 。这也是传统循环的缺点。当然传统循环更加的灵活,但其灵活性并不能掩盖他的问题。return、break、continue能直接改变循环的执行流程,强迫我们不仅要理解业务逻辑,同时也要了解循环是怎样工作的。
Java8通过引入stream指令,我们可以在集合上使用强大的函数式操作。现在我们来看看怎样将传统循环转变为更简洁,更具有可读性的代码。
这里将会创建一个Article类,他有三个成员变量:title、author、tags:
private class Article { private final String title;
private final String author;
private final List<String> tags; private Article(String title, String author, List<String> tags) {
this.title = title;
this.author = author;
this.tags = tags;
} public String getTitle() {
return title;
} public String getAuthor() {
return author;
} public List<String> getTags() {
return tags;
}
}
每个例子都会包括一个传统循环的解决方案,和Java8函数式编程的解决方案。
在第一个例子里面,将会在Article集合中寻找tag包含"Java"的第一个对象:
传统循环的解决方案:
public Article getFirstJavaArticle(){
for(Article article : articles){
if(article.getTags().contains("Java")){
return article;
}
}
return null;
}
Java8的解决方案:
public Optional<String> getFirstJavaArticle(){
return articles.stream().filter(article -> article.getTags.contains("Java")).findFirst();
}
首先我们使用filter操作找到所有符合条件的Article,然后调用findFirst()方法得到第一个。因为stream是惰性的而且filter返回了一个stream,因此方法只有在找到第一个匹配时才会去处理这个元素。
现在让我们尝试获取所有匹配的元素。
传统循环解决方案:
public List<Article> getAllJavaArticles() { List<Article> result = new ArrayList<>(); for (Article article : articles) {
if (article.getTags().contains("Java")) {
result.add(article);
}
} return result;
}
Java8解决方案:
public List<Article> getAllJavaArticles() {
return articles.stream().filter(article -> article.getTags.contains("Java")).collect(Collectors.toList());
}
在这个例子中我们使用了 collect 方法去筛选stream,而不是自己声明一个集合,并将匹配的参数追加到集合中。
到目前为止都不错,现在是时候来展现 stream api真正的魅力了!
让我们基于author将articles进行分组。
传统循环解决方案:
public Map<String,List<Article>> groupByAuthor(){
Map<String,List<Article>> result = new HashMap<>();
for(Article article : articles){
if(result.containsKey(article.getAuthor)){
result.get(article.getAuthor).add(article);
}else{
ArrayList<Article> articles = new ArrayList<>();
articles.add(article);
result.put(article.getAuthor(), articles);
}
}
}
Java8解决方案:
public Map<String, List<Article>> groupByAuthor() {
return articles.stream().collect(Collectors.groupingBy(Article::getAuthor));
}
通过使用groupingBy操作和getAuthor的方法引用,我们得到了整洁并且可读性高的代码。
现在,让我们在集合中找到Article所有的不重复的tags。
首先时传统循环方案:
public Set<String> getDistinctTags(){
Set<String> result = new HashSet<>();
for(Article article : articles){
result.addAll(article.getTags());
}
return result;
}
Java8解决方案:
public Set<String> getDistinctTags(){
return articles.stream().flatMap(article -> article.getTags().stream()).collect(Collectors.toSet());
}
flatMap帮助我们获取结果流中的tag集合,然后用collect方法创建一个Set并返回结果。
函数式编程拥有无限的可能,这四个例子的目的是怎样将循环替换成更可读的代码。你应该仔细查看stream API,因为相比api这文章仅仅只是皮毛而已。
*英文链接:deadCodeRising
*原创译文
[译]Java8:循环与函数式编程的更多相关文章
- 从java8 说起函数式编程
写在前面 为什么要用函数式编程.看例子: final List<BigDecimal> prices = Arrays.asList( new BigDecimal("10&qu ...
- Java8新特性--函数式编程
在jdk8中什么是函数式接口: 1.被@FunctionalInterface注解修饰的. 2.接口里边只有一个非default的方法. 满足以上2个条件的即为函数式接口,ps:即使一个接口没有被@F ...
- Java8 新特性 —— 函数式编程
本文部分摘录自 On Java 8 概述 通常,传递给方法的数据不同,结果也不同.同样的,如果我们希望方法被调用时的行为不同,该怎么做呢?结论是:只要能将代码传递给方法,那么就可以控制方法的行为. 说 ...
- java8 array、list操作 汇【4】)- Java8 Lambda表达式 函数式编程
int tmp1 = 1; //包围类的成员变量 static int tmp2 = 2; //包围类的静态成员变量 //https://blog.csdn.net/chengwangbaiko/ar ...
- [译]java8新特性:函数式编程(functional programming)的优点
Java8引入了函数式编程,他对java是一个极大的扩展.Java从此不在是一个单纯的面向对象语言,现在他同时混合了函数式编程.这是巨大的改变,需要我们调整面对对象的编程习惯,以适应这些变化. 但是为 ...
- [一] java8 函数式编程入门 什么是函数式编程 函数接口概念 流和收集器基本概念
本文是针对于java8引入函数式编程概念以及stream流相关的一些简单介绍 什么是函数式编程? java程序员第一反应可能会理解成类的成员方法一类的东西 此处并不是这个含义,更接近是数学上的 ...
- 重识Java8函数式编程
前言 最近真的是太忙忙忙忙忙了,很久没有更新文章了.最近工作中看到了几段关于函数式编程的代码,但是有点费解,于是就准备总结一下函数式编程.很多东西很简单,但是如果不总结,可能会被它的各种变体所困扰.接 ...
- JavaScript ES6函数式编程(一):闭包与高阶函数
函数式编程的历史 函数的第一原则是要小,第二原则则是要更小 -- ROBERT C. MARTIN 解释一下上面那句话,就是我们常说的一个函数只做一件事,比如:将字符串首字母和尾字母都改成大写,我们此 ...
- 【JS】394- 简明 JavaScript 函数式编程-入门篇
转载自公众号"程序员成长指北" 写在开头 本文较长,总共分为三大部分:(对于函数式编程以及其优点有一定理解的童鞋,可以直接从 第二部分 开始阅读) 第一部分:首先会通过实际代码介绍 ...
随机推荐
- UGUI 代码 动态添加 Event Trigger 的事件
Additionally, if you need more than just the events provided by default, I'd suggest instead attachi ...
- 获取web服务器路径的方法 getResourceAsStream
1.先获取 serlvetContext对象 2.调用getResourceAsStream 在方法里 "\"表示当前web的根目录 还要拼接上具体的文件路径 ServletC ...
- ES mapping的写入与查看
Elasticsearch索引mapping的写入.查看与修改 https://blog.csdn.net/napoay/article/details/52012249 首先创建一个索引: curl ...
- BZOJ4567 SCOI2016背单词(trie+贪心)
倒过来变成查询前缀.考虑怎么排序.第一条代价n*n就相当于inf,说明一个单词的所有前缀都要排在它前面.那么串的依赖关系就是trie的结构.二三条说明代价是Σidi-idfa,那么显然最后的编号应该是 ...
- AOJ.502 不只是水仙花
不只是水仙花 Time Limit: 1000 ms Case Time Limit: 1000 ms Memory Limit: 64 MB Total Submission: 1196 Submi ...
- React context基本用法
React的context就是一个全局变量,可以从根组件跨级别在React的组件中传递.React context的API有两个版本,React16.x之前的是老版本的context,之后的是新版本的 ...
- BZOJ day8
好吧,, 补一天题解. 1001 狼抓兔子 妥妥的网络流啊,难度仅次于草地排水,边都给出来了.就是注意反向边也要有流量就行. 1007 水平可见直线 这个题按斜率排序(注意不是绝对值),然后将直线入 ...
- 【BZOJ 3165】 [Heoi2013]Segment 李超线段树
所谓李超线段树就是解决此题一类的问题(线段覆盖查询点最大(小)),把原本计算几何的题目变成了简单的线段树,巧妙地结合了线段树的标记永久化与标记下传,在不考虑精度误差的影响下,打法应该是这样的. #in ...
- ubuntu下使用sudo 出现unable to resolve host 解决方法
Linux 环境, 假设这台机器名字叫dev(机器的hostname), 每次执行sudo 就出现这个警告讯息:sudo: unable to resolve host dev虽然sudo 还是可以正 ...
- Hyperledger Fabric架构详解
区块链开源实现HYPERLEDGER FABRIC架构详解 区块链开源实现HYPERLEDGER FABRIC架构详解 2018年5月26日 陶辉 Comments 10 Comments hyper ...