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:循环与函数式编程的更多相关文章

  1. 从java8 说起函数式编程

    写在前面 为什么要用函数式编程.看例子: final List<BigDecimal> prices = Arrays.asList( new BigDecimal("10&qu ...

  2. Java8新特性--函数式编程

    在jdk8中什么是函数式接口: 1.被@FunctionalInterface注解修饰的. 2.接口里边只有一个非default的方法. 满足以上2个条件的即为函数式接口,ps:即使一个接口没有被@F ...

  3. Java8 新特性 —— 函数式编程

    本文部分摘录自 On Java 8 概述 通常,传递给方法的数据不同,结果也不同.同样的,如果我们希望方法被调用时的行为不同,该怎么做呢?结论是:只要能将代码传递给方法,那么就可以控制方法的行为. 说 ...

  4. java8 array、list操作 汇【4】)- Java8 Lambda表达式 函数式编程

    int tmp1 = 1; //包围类的成员变量 static int tmp2 = 2; //包围类的静态成员变量 //https://blog.csdn.net/chengwangbaiko/ar ...

  5. [译]java8新特性:函数式编程(functional programming)的优点

    Java8引入了函数式编程,他对java是一个极大的扩展.Java从此不在是一个单纯的面向对象语言,现在他同时混合了函数式编程.这是巨大的改变,需要我们调整面对对象的编程习惯,以适应这些变化. 但是为 ...

  6. [一] java8 函数式编程入门 什么是函数式编程 函数接口概念 流和收集器基本概念

      本文是针对于java8引入函数式编程概念以及stream流相关的一些简单介绍 什么是函数式编程?   java程序员第一反应可能会理解成类的成员方法一类的东西 此处并不是这个含义,更接近是数学上的 ...

  7. 重识Java8函数式编程

    前言 最近真的是太忙忙忙忙忙了,很久没有更新文章了.最近工作中看到了几段关于函数式编程的代码,但是有点费解,于是就准备总结一下函数式编程.很多东西很简单,但是如果不总结,可能会被它的各种变体所困扰.接 ...

  8. JavaScript ES6函数式编程(一):闭包与高阶函数

    函数式编程的历史 函数的第一原则是要小,第二原则则是要更小 -- ROBERT C. MARTIN 解释一下上面那句话,就是我们常说的一个函数只做一件事,比如:将字符串首字母和尾字母都改成大写,我们此 ...

  9. 【JS】394- 简明 JavaScript 函数式编程-入门篇

    转载自公众号"程序员成长指北" 写在开头 本文较长,总共分为三大部分:(对于函数式编程以及其优点有一定理解的童鞋,可以直接从 第二部分 开始阅读) 第一部分:首先会通过实际代码介绍 ...

随机推荐

  1. Beat 冲刺 (3/7)

    队名:起床一起肝活队 组长博客:博客链接 作业博客:班级博客本次作业的链接 组员情况 组员1(队长):白晨曦 过去两天完成了哪些任务 描述: 1.界面的修改与完善 展示GitHub当日代码/文档签入记 ...

  2. bbbbbeta

    about beta 写在开头:(小声bb,无任何专业知识) 好了正文开始了 = = beta冲刺对于来说可能是让我觉得非常有成就感的叭,相比于alpha,每天都能写代码的感觉真好鸭(认真脸)(虽然天 ...

  3. Android问题:could not install *smartsocket* listener;Address already in use

     今天启动genymotion后,发现没有ip地址,运行项目时报错:     可见,没有连接到模拟器,无法运行,而先前说过没有ip,自然而然连接不上,   解决放法:将资源管理器打开,将adb全部退出 ...

  4. java线程(1)——三种创建线程的方式

    前言 线程,英文Thread.在java中,创建线程的方式有三种: 1.Thread 2.Runnable 3.Callable 在详细介绍下这几种方式之前,我们先来看下Thread类和Runnabl ...

  5. password & Encryption

    password & Encryption cipher https://dev.tencent.com/login

  6. C#中的String.Format方法

    定义String.Format是将指定的String类型的数据中的每个格式项替换为相应对象的值的文本等效项.(1)string p1="xiaomeng";string p2=&q ...

  7. BZOJ4651 NOI2016网格(割点)

    首先显然可以通过孤立角落里的跳蚤使其不连通,所以只要有解答案就不会大于2.同样显然的一点是当且仅当跳蚤数量<=2且连通时无解.做法其实也很显然了:特判无解,若跳蚤不连通输出0,否则看图中是否无割 ...

  8. Oracle 同环比排除分母0

    A 本期 B 同期(环期) 同比(环比) =  (A-B)/B DECODE(NVL(B,0),0,0,ROUND(((A-B)/B),4)), --环比 DECODE(NVL(B),0,0,ROUN ...

  9. [LeetCode] decode ways 解码方式

    A message containing letters fromA-Zis being encoded to numbers using the following mapping: 'A' -&g ...

  10. 洛谷 P2893 [USACO08FEB]修路Making the Grade 解题报告

    P2893 [USACO08FEB]修路Making the Grade 题目描述 A straight dirt road connects two fields on FJ's farm, but ...