stream流添加终端操作

本文介绍了如何在Java Stream API中避免使用reduce进行归约操作,着重讲解了filter、forEach和collect等终端操作,包括计算元素个数、遍历元素、以及将数据收集到不同类型的集合,如ArrayList、LinkedList、Set和数组。同时讨论了短路处理在stream处理中的应用和示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

stream流添加终端操作

避免使用reduce()归约操作

使用reduce()并不是最简单的归约方法。

You need to make sure that the binary operator you provide is associative, then you need to know if it has an identity element.

计算stream流中的元素个数

示例

Collection<String> strings =
        List.of("one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten");

long count =
        strings.stream()
                .filter(s -> s.length() == 3)
                .count();
System.out.println("count = " + count);

结果

count = 4

依次消费stream流中的元素

foreach()

示例1

Stream<String> strings = Stream.of("one", "two", "three", "four");
strings.filter(s -> s.length() == 3)
       .map(String::toUpperCase)
       .forEach(System.out::println);

结果

ONE
TWO

示例2

Stream<String> strings = Stream.of("one", "two", "three", "four");
List<String> result = new ArrayList<>();

strings.filter(s -> s.length() == 3)
       .map(String::toUpperCase)
       .forEach(result::add);

System.out.println("result = " + result);

结果

result = [ONE, TWO]

示例2的改写

Stream<String> strings = Stream.of("one", "two", "three", "four");

List<String> result = 
    strings.filter(s -> s.length() == 3)
           .map(String::toUpperCase)
           .collect(Collectors.toList());

jdk16可以改写成

Stream<String> strings = Stream.of("one", "two", "three", "four");

List<String> result = 
    strings.filter(s -> s.length() == 3)
           .map(String::toUpperCase)
           .toList();

注意返回的result是不可变的。

在集合或数组中收集stream流元素

Stream API提供了几种收集stream流中被处理的数据到集合中。

在你选择你所需的模式前你需要考虑以下的问题:

  • 你是否需要构建一个不变的List

  • 你是需要ArrayList还是LinkedList

  • 你是否确切的知道所处理的stream流的具体元素个数

  • 你是否需要收集到第三方或者自己定义的List

收集到ArrayList

示例

Stream<String> strings = Stream.of("one", "two", "three", "four");

List<String> result = 
    strings.filter(s -> s.length() == 3)
           .map(String::toUpperCase)
           .collect(Collectors.toList());

这是最简单的方法,但请注意当stream流中元素很多,会造成ArrayList拷贝到更大ArrayList并伴随着gc收集之前ArrayList

可以使用Collectors.toCollection()指定更大容量大ArrayList避免多次gc

Stream<String> strings = ...;

List<String> result = 
    strings.filter(s -> s.length() == 3)
           .map(String::toUpperCase)
           .collect(Collectors.toCollection(() -> new ArrayList<>(10_000)));

收集到不变的List

示例

Stream<String> strings = ...;

List<String> result = 
    strings.filter(s -> s.length() == 3)
           .map(String::toUpperCase)
           .collect(Collectors.toUnmodifiableList()));

jdk16

Stream<String> strings = ...;

List<String> result = 
    strings.filter(s -> s.length() == 3)
           .map(String::toUpperCase)
           .toList();

收集到自制的List

使用Collectors.toCollection()

Stream<String> strings = ...;

List<String> result = 
    strings.filter(s -> s.length() == 3)
           .map(String::toUpperCase)
           .collect(Collectors.toCollection(LinkedList::new));

收集到Set

可以使用Collectors.toCollection(HashSet::new)或者更简洁的Collectors.toSet(),注意这俩者还是有细微的差别,后面介绍。

Stream<String> strings = ...;

Set<String> result = 
    strings.filter(s -> s.length() == 3)
           .map(String::toUpperCase)
           .collect(Collectors.toSet());

如果你需要收集到不变的Set

Stream<String> strings = ...;

Set<String> result = 
    strings.filter(s -> s.length() == 3)
           .map(String::toUpperCase)
           .collect(Collectors.toUnmodifiableSet());

收集到数组

示例

Stream<String> strings = ...;

String[] result = 
    strings.filter(s -> s.length() == 3)
           .map(String::toUpperCase)
           .toArray(String[]::new);

System.out.println("result = " + Arrays.toString(result));

结果

result = [ONE, TWO]

提取stream流中最大和最小元素

示例

Stream<String> strings = Stream.of("one", "two", "three", "four");
String longest =
     strings.max(Comparator.comparing(String::length))
            .orElseThrow();
System.out.println("longest = " + longest);

结果

longest = three

stream流中查找元素

findFirst(), findAny()

Collection<String> strings =
        List.of("one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten");

String first =
    strings.stream()
           // .unordered()
           // .parallel()
           .filter(s -> s.length() == 3)
           .findFirst()
           .orElseThrow();

System.out.println("first = " + first);

结果

first = one

检查stream流中的元素是否与给定的Predicate匹配

  • anyMatch(predicate)只要stream流中有一个元素匹配就返回true

  • allMatch(predicate)stream流中所有元素都匹配才返回true

  • noneMatch(predicate)stream流中没有一个元素匹配才返回true

Collection<String> strings =
    List.of("one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten");

boolean noBlank  = 
        strings.stream()
               .allMatch(Predicate.not(String::isBlank));
boolean oneGT3   = 
        strings.stream()
               .anyMatch(s -> s.length() == 3);
boolean allLT10  = 
        strings.stream()
               .noneMatch(s -> s.length() > 10);
        
System.out.println("noBlank = " + noBlank);
System.out.println("oneGT3  = " + oneGT3);
System.out.println("allLT10 = " + allLT10);

结果

noBlank = true
oneGT3  = true
allLT10 = true

stream流的短路处理

stream流的终端处理分类:一些需要处理完所有的元素才返回,例如count(), max(), min(), average(), forEach(), toList(), toArray()等。一些不需要处理完所有数据即可返回,例如findFirst(), findAny(), anyMatch(), allMatch(), noneMatch()

短路处理:无需处理stream流的所有元素即可产生结果。

### Java Stream API 的并行操作 #### 并行简介 在 Java 8 中引入了 Stream API,这为处理集合数据提供了一种强大且简洁的方法。Stream API 支持顺序和并行两种模式来执行操作序列。对于大规模数据集而言,并行可以利用多核处理器的优势提高程序运行效率[^3]。 #### 创建并行 可以通过调用 `stream.parallel()` 或者直接使用集合对象上的 `parallelStream` 方法创建一个并行实例: ```java List<String> list = Arrays.asList("apple", "banana", "orange"); // 方式一:通过stream().parallel()转换成并行 list.stream().parallel(); // 方式二:直接获取并行 list.parallelStream(); ``` #### 执行中间操作终端操作 当定义好了一个并行之后,就可以像普通的串行那样链式地添加各种中间操作(如过滤、映射等),最后再指定一个终止操作完成整个水线的操作。需要注意的是,在某些情况下,并行可能会改变元素之间的相对顺序;如果希望保持原有顺序,则可以在创建时传入参数 `Spliterator.ORDERED` 来确保有序性[^5]。 下面是一个简单的例子展示了如何使用并行来进行文件读取并将每一行转为大写形式打印出来: ```java import java.io.BufferedReader; import java.nio.file.Files; public class ParallelStreamExample { public static void main(String[] args) throws Exception { try (BufferedReader reader = Files.newBufferedReader(inputFile.toPath())) { reader.lines() .parallel() // 将设置为并行模式 .map(String::toUpperCase) .forEach(System.out::println); } } } ``` 在这个案例里,`lines()` 返回的是由缓冲区中的各行组成的,接着将其设为并行方式并通过 map 函数把每条记录都变成全大写字母的形式,最终遍历输出结果到控制台。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值