跳转至

Java 17 Stream 全面解析

简介

Java 17 作为 Java 生态系统中的一个重要版本,带来了许多实用的特性和改进,其中 Stream API 是 Java 8 引入的一个强大工具,在 Java 17 中依然发挥着重要作用。Stream API 提供了一种高效且简洁的方式来处理集合数据,它允许开发者以声明式的方式对数据进行过滤、映射、排序等操作,大大提高了代码的可读性和可维护性。本文将深入介绍 Java 17 Stream 的基础概念、使用方法、常见实践以及最佳实践,帮助读者更好地掌握这一强大的工具。

目录

  1. 基础概念
  2. 使用方法
  3. 常见实践
  4. 最佳实践
  5. 小结
  6. 参考资料

基础概念

什么是 Stream

Stream 是 Java 8 引入的一个抽象概念,它代表了一系列支持各种聚合操作的元素序列。Stream 本身并不存储数据,而是对数据源(如集合、数组等)进行操作,它提供了一种流式处理数据的方式,使得数据处理更加高效和简洁。

Stream 的特点

  • 不存储数据:Stream 不存储元素,它只是对数据源进行操作。
  • 一次性使用:Stream 只能被消费一次,一旦被使用,就不能再次使用。
  • 延迟执行:Stream 的操作分为中间操作和终端操作,中间操作是延迟执行的,只有在终端操作被调用时,中间操作才会真正执行。

Stream 的操作类型

  • 中间操作:返回一个新的 Stream,用于对数据进行过滤、映射等操作,如 filter()map()sorted() 等。
  • 终端操作:触发 Stream 的执行,并产生一个结果或副作用,如 forEach()collect()count() 等。

使用方法

创建 Stream

可以通过多种方式创建 Stream,以下是一些常见的创建方式:

import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

public class StreamCreationExample {
    public static void main(String[] args) {
        // 从集合创建 Stream
        List<String> list = Arrays.asList("apple", "banana", "cherry");
        Stream<String> streamFromList = list.stream();

        // 从数组创建 Stream
        String[] array = {"apple", "banana", "cherry"};
        Stream<String> streamFromArray = Arrays.stream(array);

        // 创建空 Stream
        Stream<String> emptyStream = Stream.empty();

        // 使用 Stream.of() 创建 Stream
        Stream<String> streamFromValues = Stream.of("apple", "banana", "cherry");
    }
}

中间操作

中间操作返回一个新的 Stream,以下是一些常见的中间操作:

import java.util.Arrays;
import java.util.List;

public class IntermediateOperationsExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        // 过滤操作,只保留偶数
        List<Integer> evenNumbers = numbers.stream()
                .filter(n -> n % 2 == 0)
                .toList();
        System.out.println("Even numbers: " + evenNumbers);

        // 映射操作,将每个元素乘以 2
        List<Integer> doubledNumbers = numbers.stream()
                .map(n -> n * 2)
                .toList();
        System.out.println("Doubled numbers: " + doubledNumbers);

        // 排序操作,按降序排序
        List<Integer> sortedNumbers = numbers.stream()
                .sorted((a, b) -> b - a)
                .toList();
        System.out.println("Sorted numbers in descending order: " + sortedNumbers);
    }
}

终端操作

终端操作触发 Stream 的执行,并产生一个结果或副作用,以下是一些常见的终端操作:

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

public class TerminalOperationsExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

        // forEach 操作,遍历每个元素
        numbers.stream()
                .forEach(n -> System.out.print(n + " "));
        System.out.println();

        // count 操作,统计元素个数
        long count = numbers.stream()
                .count();
        System.out.println("Number of elements: " + count);

        // findFirst 操作,查找第一个元素
        Optional<Integer> firstElement = numbers.stream()
                .findFirst();
        System.out.println("First element: " + firstElement.orElse(0));
    }
}

常见实践

数据过滤和筛选

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class FilteringExample {
    public static void main(String[] args) {
        List<String> fruits = Arrays.asList("apple", "banana", "cherry", "date");

        // 过滤出长度大于 5 的水果
        List<String> longFruits = fruits.stream()
                .filter(fruit -> fruit.length() > 5)
                .collect(Collectors.toList());
        System.out.println("Long fruits: " + longFruits);
    }
}

数据映射和转换

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class MappingExample {
    public static void main(String[] args) {
        List<String> words = Arrays.asList("hello", "world");

        // 将每个单词转换为大写
        List<String> upperCaseWords = words.stream()
                .map(String::toUpperCase)
                .collect(Collectors.toList());
        System.out.println("Upper case words: " + upperCaseWords);
    }
}

数据聚合和统计

import java.util.Arrays;
import java.util.List;

public class AggregationExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

        // 计算所有元素的总和
        int sum = numbers.stream()
                .mapToInt(Integer::intValue)
                .sum();
        System.out.println("Sum of numbers: " + sum);
    }
}

最佳实践

合理使用中间操作和终端操作

尽量将多个中间操作组合在一起,避免频繁调用终端操作,因为中间操作是延迟执行的,可以提高性能。

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class BestPracticeExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

        // 组合多个中间操作
        List<Integer> result = numbers.stream()
                .filter(n -> n % 2 == 0)
                .map(n -> n * 2)
                .collect(Collectors.toList());
        System.out.println("Result: " + result);
    }
}

避免使用副作用

在 Stream 操作中,尽量避免使用有副作用的操作,如修改外部变量等,因为 Stream 是为并行处理设计的,副作用可能会导致线程安全问题。

import java.util.Arrays;
import java.util.List;

public class AvoidSideEffectsExample {
    public static void main(String[] args) {
        List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

        // 不使用副作用的方式计算总和
        int sum = numbers.stream()
                .mapToInt(Integer::intValue)
                .sum();
        System.out.println("Sum: " + sum);
    }
}

小结

Java 17 Stream 是一个强大的工具,它提供了一种高效且简洁的方式来处理集合数据。通过本文的介绍,我们了解了 Stream 的基础概念、使用方法、常见实践以及最佳实践。在实际开发中,合理使用 Stream 可以提高代码的可读性和可维护性,同时也能提升程序的性能。希望本文能帮助读者更好地掌握 Java 17 Stream 的使用。

参考资料

  • 《Effective Java》(第三版)
  • 《Java 8 in Action》