本文由 ImportNew - 进林 翻译自 deadcoderising。欢迎加入翻译小组。转载请见文末要求。

正如我之前所写的,Java 8中的新功能特性改变了游戏规则。对Java开发者来说这是一个全新的世界,并且是时候去适应它了。

在这篇文章里,我们将会去了解传统循环的一些替代方案。在Java 8的新功能特性中,最棒的特性就是允许我们去表达我们想要完成什么而不是要怎样做。这正是循环的不足之处。要确保循环的灵活性是需要付出代价的。return、break 或者 continue都会显著地改变循环的实际表现。这迫使我们不仅要清楚我们要实现怎样的代码,还要了解循环是怎样工作的。

在介绍Java 8的流(Stream)时,我们学会了一些集合操作的实用技巧。现在我们要看看怎样把这些循环转换为更简洁,可读性更高的代码。

开始编码!

好吧,讲的够多了,是时候展示一些例子了!

这次我们要以文章为例子。一篇文章拥有一个标题,一个作者和几个标签。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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;
        }
    }

每个例子都会包含一个使用传统循环的方案和一个使用Java 8新特性的方案。

在第一个例子里,我们要在集合中查找包含“Java”标签的第一篇文章。

看一下使用for循环的解决方案。

1
2
3
4
5
6
7
8
9
10
public Article getFirstJavaArticle() {
 
    for (Article article : articles) {
        if (article.getTags().contains("Java")) {
            return article;
        }
    }
 
    return null;
}

现在我们使用Stream API的相关操作来解决这个问题。

1
2
3
4
5
public Optional<Article> getFirstJavaArticle() { 
    return articles.stream()
        .filter(article -> article.getTags().contains("Java"))
        .findFirst();
    }

是不是很酷?我们首先使用 filter 操作去找到所有包含Java标签的文章,然后使用 findFirst() 操作去获取第一次出现的文章。因为Stream是“延迟计算”(lazy)的并且filter返回一个流对象,所以这个方法仅在找到第一个匹配元素时才会处理元素。

现在,让我们获取所有匹配的元素而不是仅获取第一个。

首先使用for循环方案。

1
2
3
4
5
6
7
8
9
10
11
12
public List<Article> getAllJavaArticles() {
 
    List<Article> result = new ArrayList<>();
 
    for (Article article : articles) {
        if (article.getTags().contains("Java")) {
            result.add(article);
        }
    }
 
    return result;
}

使用Stream操作的方案。

1
2
3
4
5
public List<Article> getAllJavaArticles() { 
    return articles.stream()
        .filter(article -> article.getTags().contains("Java"))
        .collect(Collectors.toList());
    }

在这个例子里我们使用 collection 操作在返回流上执行少量代码而不是手动声明一个集合并显式地添加匹配的文章到集合里。

到目前为止还不错。是时候举一些突出Stream API强大的例子了。

根据作者来把所有的文章分组。

照旧,我们使用循环方案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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);
        }
    }
 
    return result;
}

我们能否找到一个使用流操作的简洁方案来解决这个问题?

1
2
3
4
public Map<String, List<Article>> groupByAuthor() { 
    return articles.stream()
        .collect(Collectors.groupingBy(Article::getAuthor));
}

很好!使用 groupingBy 操作和 getAuthor 方法,我们得到了更简洁、可读性更高的代码。

现在,我们查找集合中所有不同的标签。

我们从使用循环的例子开始。

1
2
3
4
5
6
7
8
9
10
public Set<String> getDistinctTags() {
 
    Set<String> result = new HashSet<>();
 
    for (Article article : articles) {
        result.addAll(article.getTags());
    }
 
    return result;
}

好,我们来看看如何使用Stream操作来解决这个问题。

1
2
3
4
5
public Set<String> getDistinctTags() { 
    return articles.stream()
        .flatMap(article -> article.getTags().stream())
        .collect(Collectors.toSet());
}

棒极了!flatmap 帮我把标签列表转为一个返回流,然后我们使用 collect 去创建一个集合作为返回值。

一切皆有可能

以上的就是如何使用可读性更高的代码代替循环的例子。务必仔细看看Stream API,因为这篇文章仅仅提到它的一些皮毛而已。

更新

收到solarfuse和dhruvgairola的评论后,更新了getDistinctTags()例子,使用集合(Set)作为返回集合。

原文链接: deadcoderising 翻译: ImportNew.com进林
译文链接: http://www.importnew.com/14841.html

转载自连接:http://www.importnew.com/14841.html

Java 8:用Stream来循环集合的更多相关文章

  1. java 数据类型:Stream流 对象转换为集合collect(Collectors.toList()) ;常用方法count,limit,skip,concat,max,min

    集合对象.stream() 获取流对象,对元素批处理(不改变原集合) 集合元素循环除了用for循环取出,还有更优雅的方式.forEach 示例List集合获取Stream对象进行元素批处理 impor ...

  2. JAVA 8 主要新特性 ----------------(六)集合Stream API

    一.简介Stream Java8中有两大最为重要的改变.第一个是 Lambda 表达式:另外一 个则是 Stream API(java.util.stream.*).Stream 是 Java8 中处 ...

  3. java通过Stream对list集合分组

    java通过Stream对list集合分组 现在有一个List集合,想对该集合中的数据分组处理,想到java8中的stream,就搞来试试,非常给力!例子如下 1 2 3 4 5 6 7 8 9 10 ...

  4. Android java程序员必备技能,集合与数组中遍历元素,增强for循环的使用详解及代码

    Android java程序员必备技能,集合与数组中遍历元素, 增强for循环的使用详解及代码 作者:程序员小冰,CSDN博客:http://blog.csdn.net/qq_21376985 For ...

  5. Java 8 特性 —— Stream

    Stream 是用函数式编程方式在集合类上进行复杂操作的工具,其集成了Java 8 中的众多新特性之一的聚合操作,开发者可以更容易地使用Lambda表达式,并且更方便地实现对集合的查找.遍历.过滤以及 ...

  6. Java高级特性 第1节 集合框架和泛型

    Java中,存储多个同类型的数据,可以用数组来实现,但数组有一些缺陷: 数组长度固定不变,布恩那个很好的适应元素数量动态变化的情况 可以通过数组.length获取数组长度,却无法直接获取数组中实际存储 ...

  7. 无情的Java 8 之 Stream和lambda表达式篇

    不好意思,最近刷小视频刷的有点上头 看到这图就不自觉的要来一句:"卧槽,无情" 好了,我要开始正经了 JAVA 8 已经推出有一段时间了, 相比之前, 我们操作集合的方式应该是这样 ...

  8. java中的Stream流

    java中的Stream流 说到Stream便容易想到I/O Stream,而实际上,谁规定"流"就一定是"IO流"呢?在Java 8中,得益于Lambda所带 ...

  9. JAVA中简单的for循环竟有这么多坑,你踩过吗

    JAVA中简单的for循环竟有这么多坑,你踩过吗 实际的业务项目开发中,大家应该对从给定的list中剔除不满足条件的元素这个操作不陌生吧? 很多同学可以立刻想出很多种实现的方式,但你想到的这些实现方式 ...

随机推荐

  1. 使输入框(input  & textarea)变为只可读状态readonly="readonly",禁用输入框disabled="disabled"

    使输入框变为只可读状态 readonly="readonly" <input class="select-city" placeholder=" ...

  2. 第二十二篇 jQuery 学习4 内容和属性

    jQuery 内容和属性   这节课,我们学习使用jQuery来控制元素的内容.值和属性.   html() 控制所选元素的内容(包括HTML标记): text() 控制所选元素的内容: val() ...

  3. HAproxy企业应用,TCP/HTTP动静分离

    HAProxy的是一个免费的.开源的的tcp/http反向代理工具.负载均衡器,是一个企业非常快速和可靠的安全的解决方案,提供高可用性.高并发性,负载均衡和代理对TCP和基于HTTP的应用程序.它特别 ...

  4. PyCharm上unittest 测试用例两种执行方式

    每次讲到unittest测试框架的时候,经常有同学在群里反映,为啥我的运行不是按照我往suite里添加的用例顺序执行的,为什么别人的能跑出来报告,我的就不行... 当然,首先确认代码是OK的,如果代码 ...

  5. MVC中 global.asax

    MVC框架下 global.asax 页面的事件 这些事件被触发的 顺序是: Application_BeginRequest Application_AuthenticateRequest Appl ...

  6. SVN 安装教程

    安装包:http://pan.baidu.com/s/1kTTcbJp 安装步骤看这个博主的就好了: http://www.cnblogs.com/xing901022/p/4399382.html ...

  7. Codeforces 1000 组合数可行线段倒dp 边双联通缩点求树直径

    A /*Huyyt*/ #include<bits/stdc++.h> #define mem(a,b) memset(a,b,sizeof(a)) using namespace std ...

  8. highcharts的基本使用(转载)

    1 概述 Highcharts是一个跨浏览器的JavaScript图表控件,支持柱状图.趋势图.面积图.饼图.环形图.组合图.堆积图.散点图. Highcharts图表的基本功能,只需要引入两个JS类 ...

  9. 微信小程序 点击事件 传递参数

    wxml: data-参数名="值" bindtap="函数名" <view class="buy-button {{cap_select == ...

  10. 高性能mysql 第11章 可扩展的mysql

    可扩展性的定义:当增加资源以获得执行更多的工作系统能获得划算的同等提升. 向上扩展(垂直扩展):提升服务器的硬件性能. 向外扩展(水平扩展):一般都是复制,拆分,数据分片(sharding). 复制: ...