前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用 Java 8 中的 Stream ,可以让你写代码事半功倍

使用 Java 8 中的 Stream ,可以让你写代码事半功倍

作者头像
万猫学社
发布2023-09-01 16:56:46
1380
发布2023-09-01 16:56:46
举报

Stream

Java 8 中一个主要的新功能是引入了流(Stream)功能。在java.util.stream中包含用于处理元素序列的类。其中,最重要的类是Stream<T>。下面我们就来看看如何使用现有的数据源创建流。

创建Stream

可以使用 stream()of() 方法从不同的数据源(例如:集合、数组)创建流:

代码语言:javascript
复制
String[] arr = new String[]{"万", "猫", "学", "社"};
Stream<String> stream = Arrays.stream(arr);
stream = Stream.of("万", "猫", "学", "社");

Collection 接口新增了一个 stream() 默认方法,允许使用任何集合作为数据源来创建 Stream<T>

代码语言:javascript
复制
List<String> list = new ArrayList();
list.add("万");
list.add("猫");
list.add("学");
list.add("社");
Stream<String> stream = list.stream();

在多线程中使用Stream

Stream 还通过提供 parallelStream() 方法来简化多线程操作,该方法以并行模式运行对流元素的操作。

下面的代码可以对流的每个元素并行运行 doWork() 方法:

代码语言:javascript
复制
List<String> list = new ArrayList();
list.add("万");
list.add("猫");
list.add("学");
list.add("社");
list.parallelStream().forEach(element -> doWork(element));

接下来,我们将介绍一些基本的 Stream 操作。

Stream 操作

在流上可以执行许多有用的操作。它们被分为中间操作(返回 Stream<T>)和终端操作(返回明确定义类型的结果),中间操作允许链接。

我需要注意的是,流上的操作不会改变数据源。

下面是一个简单的例子:

代码语言:javascript
复制
List<String> list = new ArrayList();
list.add("万");
list.add("猫");
list.add("学");
list.add("社");
long count = list.stream().distinct().count();

在上面的例子中,distinct() 方法表示一个中间操作,它创建了前一个流的唯一元素的新流。而 count() 方法是一个终端操作,它返回流的大小。

迭代

Stream 帮助我们替代了 for、for-each 和 while 循环。它可以让我们把精力集中在操作的逻辑上,而不是在迭代元素序列上。

比如下面的代码:

代码语言:javascript
复制
for (String string : list) {
    if (string.contains("猫")) {
        return true;
    }
}

这段代码只需要一行 Stream 代码就可以实现:

代码语言:javascript
复制
boolean isExist = list.stream().anyMatch(element -> element.contains("猫"));

过滤

filter() 方法可以让我们选择满足谓词条件的元素流。

比如下面的代码:

代码语言:javascript
复制
List<String> list = new ArrayList();
list.add("万");
list.add("猫");
list.add("学");
list.add("社");
Stream<String> stream = list.stream().filter(element -> element.contains("猫"));

在上面的例子中,创建了一个 List<String>Stream<String>,查找该流中所有包含字符“猫”的元素,并创建一个只包含筛选后元素的新流。

映射

为了通过将特殊函数应用于流元素来转换它们,并将这些新元素收集到流中,我们可以使用 map() 方法。

比如下面的代码:

代码语言:javascript
复制
List<String> list = new ArrayList();
list.add("1");
list.add("2");
list.add("3");
Stream<Integer> stream = list.stream().map(str -> Integer.valueOf(str));

在上面的例子中,通过对初始流的每个元素应用特定的 lambda 表达式将 Stream<String> 转换为 Stream<Integer>

如果您有一个流,其中每个元素都包含其自己的元素序列,并且您想创建这些内部元素的流,则应使用 flatMap() 方法。

比如下面的代码:

代码语言:javascript
复制
public class Writer {
    private String name;
    private List<String> books;
}
代码语言:javascript
复制
List<Writer> writers = new ArrayList<>();
writers.add(new Writer());
Stream<String> stream = writers.stream().flatMap(writer -> writer.getBooks().stream());

在上面的例子中,我们有一个类型为 Writer 的元素列表。Writer 类包含一个类型为 List<String> 的字段 books。使用 flatMap() 方法,字段 books 中的每个元素将被提取并添加到新的结果流中。之后,最开始的 Stream将会丢失。

匹配

Stream 提供了一组方便的工具,根据一些谓词验证一个序列的元素。我们可以使用以下方法之一:

  • anyMatch():只要有一个条件满足即返回true
  • allMatch():必须全部都满足才会返回true
  • noneMatch():全都不满足才会返回true

它们都返回 boolean 的终端操作。

比如下面的代码:

代码语言:javascript
复制
List<String> list = new ArrayList();
list.add("万");
list.add("猫");
list.add("学");
list.add("社");
list.stream().anyMatch(element -> element.contains("万")); // true
list.stream().allMatch(element -> element.contains("万")); // false
list.stream().noneMatch(element -> element.contains("万")); // false

对于空的 Stream,无论给定的谓词是什么,allMatch() 方法都将返回 true:

代码语言:javascript
复制
Stream.empty().anyMatch(Objects::nonNull); // false

这是一个合理的值,因为我们找不到不满足谓词的任何元素。

同样地,对于空的 Stream,anyMatch() 方法总是返回 false:

代码语言:javascript
复制
Stream.empty().anyMatch(Objects::nonNull); // false

同样地,这也是合理的,因为我们找不到满足这个条件的元素。

合并

我可以使用类型为 Stream 的 reduce() 方法,根据指定的函数将一系列元素合并为某个值。这个方法有两个参数:第一个是起始值,第二个是累加器函数。

比如下面的代码:

代码语言:javascript
复制
List<Integer> integers = Arrays.asList(1, 2, 3);
Integer reduced = integers.stream().reduce(4, (a, b) -> a + b);

在上面的例子中,有一个 List<Integer>,我们将这些元素加起来,并加上一个初始的整数(在这个例子中是4)。那么,运行以下代码的结果是10(4 + 1 + 2 + 3)。

收集

在 Stream 类型中,也可以通过 collect() 方法来进行收集。这个操作非常方便,可以将一个流转换为 CollectionMap,也可以将一个流表示为单个字符串。Collectors 是一个实用类,提供了几乎所有典型的收集操作的解决方案。对于一些不太常见的任务,可以创建自定义的收集器。

下面的代码使用终端操作 collect()Stream<String> 转换为 List<String>

代码语言:javascript
复制
List<String> resultList 
  = list.stream().map(element -> element.toUpperCase()).collect(Collectors.toList());

最后

Stream 的高级示例非常丰富,本文的目的是为了让我们快速了解 Stream 功能的用法,并启发我们继续探索和深入学习。

Stream 是 Java 8 中非常强大和实用的 API,它为开发人员提供了一种更加简便的方式来处理数据。希望我们通过本文的介绍和示例,可以快速上手使用 Stream,并继续深入学习和探索。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-05-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 万猫学社 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Stream
    • 创建Stream
      • 在多线程中使用Stream
      • Stream 操作
        • 迭代
          • 过滤
            • 映射
              • 匹配
                • 合并
                  • 收集
                  • 最后
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档