欢迎访问宙启技术站
智能推送

Java 中如何使用 Stream API 来操作集合?

发布时间:2023-06-07 11:01:56

Stream API 是 Java 8 引入的一种新的操作集合的方法。它能让我们以一种更流畅的方式处理一系列的对象。

一、Stream 如何创建

Stream 的创建大致分为两类:

1. 通过 stream() 方法从集合中创建一个 Stream

List<String> list = Arrays.asList("apple", "banana", "cat");
Stream<String> stream = list.stream(); // 从集合中创建 Stream

2. 通过 of() 方法创建一个 Stream

Stream<String> stream = Stream.of("apple", "banana", "cat"); // 创建 Stream

二、Stream 的中间操作

Stream 的中间操作是指对集合中的元素进行筛选、排序、过滤等操作,这些操作仅进行转换,不会影响原始集合。如下是常用的中间操作:

1. filter():筛选符合条件的元素

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> newList = list.stream()
        .filter(n -> n % 2 == 0) // 筛选出偶数
        .collect(Collectors.toList()); // 转换为 List
System.out.println(newList); // [2, 4]

2. map():将集合中的元素映射为新的元素

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> newList = list.stream()
        .map(n -> n * n) // 平方
        .collect(Collectors.toList()); // 转换为 List
System.out.println(newList); // [1, 4, 9, 16, 25]

3. sorted():对集合进行排序

List<Integer> list = Arrays.asList(3, 1, 4, 2, 5);
List<Integer> newList = list.stream()
        .sorted()
        .collect(Collectors.toList()); // 转换为 List
System.out.println(newList); // [1, 2, 3, 4, 5]

4. distinct():对集合进行去重

List<Integer> list = Arrays.asList(3, 1, 4, 2, 5, 1, 2, 4);
List<Integer> newList = list.stream()
        .distinct()
        .collect(Collectors.toList()); // 转换为 List
System.out.println(newList); // [3, 1, 4, 2, 5]

5. limit():限制集合中输出元素的个数

List<Integer> list = Arrays.asList(3, 1, 4, 2, 5);
List<Integer> newList = list.stream()
        .limit(3) // 取前三个
        .collect(Collectors.toList()); // 转换为 List
System.out.println(newList); // [3, 1, 4]

6. skip():跳过前几个元素输出

List<Integer> list = Arrays.asList(3, 1, 4, 2, 5);
List<Integer> newList = list.stream()
        .skip(3) // 跳过前三个
        .collect(Collectors.toList()); // 转换为 List
System.out.println(newList); // [2, 5]

三、Stream 的终止操作

终止操作会触发 Stream 的计算并生成一个结果或者副作用,同时该操作也会关闭 Stream。

1. forEach():遍历 Stream 元素

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
list.stream().forEach(System.out::println); // 遍历并输出每个元素

2. collect():将 Stream 转换为集合

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> newList = list.stream().collect(Collectors.toList()); // 转换为 List
System.out.println(newList); // [1, 2, 3, 4, 5]

3. count():返回 Stream 元素的个数

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
long count = list.stream().count(); // 返回元素个数
System.out.println(count); // 5

4. reduce():可以将集合中的元素进行运算,最终返回一个结果

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> optional = list.stream().reduce((a, b) -> a + b); // 求和
System.out.println(optional.get()); // 15

5. min()max():返回集合中的最小值和最大值

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> optional1 = list.stream().min((a, b) -> a.compareTo(b)); // 最小值
Optional<Integer> optional2 = list.stream().max((a, b) -> a.compareTo(b)); // 最大值
System.out.println(optional1.get()); // 1
System.out.println(optional2.get()); // 5

四、Stream 的处理顺序

在 Stream API 中,中间操作和终止操作的顺序会影响最终的结果。中间操作在添加时,只是向 Stream 中添加了一些指令,并不会立即执行。只有在触发终止操作时,这些指令才会一并执行。

优化 Stream 的处理顺序,可以有效提高程序的执行效率。

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Integer result = list.stream()
        .filter(n -> {System.out.println("filter:" + n); return n % 2 == 0;})
        .map(n -> {System.out.println("map:" + n); return n * 2;})
        .findFirst()
        .get();
System.out.println(result);

以上代码会输出:

filter:1
filter:2
map:2
4

可以发现,只有在终止操作 findFirst() 被执行时,才会触发中间操作的执行。

五、Stream 的并行处理

在处理大量数据时,使用并行处理可以大大缩短程序的执行时间。

List<Integer> list = new ArrayList<>();
for (int i = 0; i < 1000000; i++) {
    list.add(i);
}

long start = System.currentTimeMillis();
long count = list.stream().filter(n -> n % 2 == 0).count();
long end = System.currentTimeMillis();

System.out.println(count);
System.out.println(end - start + "ms"); // 465ms

以上代码使用串行处理 stream(),执行时间大概在 400ms 左右。

List<Integer> list = new ArrayList<>();
for (int i = 0; i < 1000000; i++) {
    list.add(i);
}

long start = System.currentTimeMillis();
long count = list.parallelStream().filter(n -> n % 2 == 0).count();
long end = System.currentTimeMillis();

System.out.println(count);
System.out.println(end - start + "ms"); // 143ms

以上代码使用并行处理 parallelStream(),执行时间大概在 100ms 左右,性能提升了 4 倍。

六、Stream 的应用场景

Stream API 可以在很多场景下使用,它可以用来处理集合、文件、网络数据等各种数据源。

1. 对集合进行筛选、排序、过滤等操作

List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> newList = list.stream()
        .filter(n -> n % 2 == 0) // 筛选出偶数
        .sorted() // 排序
        .map(n -> n * n) // 平方
        .collect(Collectors.toList()); // 转换为 List
System.out.println(newList); // [4, 16]

2. 对文件中的数据进行处理

`java

try (Stream<String> stream = Files.lines(Paths.get("data.txt"))) {

List<String> newList = stream

.filter(line -> !line.startsWith("#")) //