Java基础 - Java函数式编程 - Stream API
Introduction
Stream API
Stream API的特性
- 声明式: 你只需描述做什么,而无需关心如何做
- 可组合: 中间操作返回一个新的Stream,因此可以将多个操作链接起来
- 一次性消费: 一个Stream只能被一个终端操作消费一次
- 支持并行化
Stream的创建
stream的创建:在使用Stream API之前,你必须先获得一个Stream实例。Collection接口提供了stream()和parallelStream()默认方法。
List<String> list = Arrays.asList("a", "b", "c");
Stream<String> sequentialStream = list.stream(); // 创建串行流
Set<Integer> set = new HashSet<>(Arrays.asList(1, 2, 3));
Stream<Integer> parallelStream = set.parallelStream(); // 创建并行流
String[] array = {"x", "y", "z"};
Stream<String> streamFromArray = Arrays.stream(array);
// 静态工厂方法创建
Stream<String> streamOf = Stream.of("apple", "banana", "cherry");Stream的中间操作
中间操作接收一个Stream,返回一个新的Stream。
filter(Predicate<T> predicate): 过滤。保留使predicate返回true的元素。
// 筛选出长度大于5的字符串
stream.filter(s -> s.length() > 5);map(Function<T, R> mapper): 映射/转换。将每个元素T转换为一个新的元素R。
// 将字符串列表转换为其长度的列表
stream.map(String::length); // 返回一个 Stream<Integer>peek(Consumer<T> action): 主要用于调试,它会对流中的每个元素执行一个操作,但不会改变流本身。
stream.peek(s -> System.out.println("Processing: " + s));sorted()/sorted(Comparator<T> comparator): 排序。limit(long maxSize): 截断流,使其元素数量不超过maxSize。distinct(): 去重。基于元素的equals()方法。
Stream的终端操作
终端操作是流水线的终点。它会触发所有惰性中间操作的执行,并产生一个最终结果或副作用(打印到控制台,调用某个服务的API等)。
惰性求值:中间操作不会立即执行。它们只是在流水线上注册了一个待执行的操作。只有当一个终端操作被调用时,整个流水线才会从源头开始,依次执行所有中间操作。
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
Stream<String> stream = names.stream()
.filter(name -> {
System.out.println("Filtering: " + name);
return name.length() > 4;
})
.map(name -> {
System.out.println("Mapping: " + name);
return name.toUpperCase();
});
// 直到下面这行终端操作被调用,上面的打印语句才会执行
String firstResult = stream.findFirst().get();
System.out.println("First result: " + firstResult);消费与副作用:对每个元素执行操作
void forEach(Consumer<? super T> action)
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.stream()
.filter(s -> s.startsWith("A"))
.forEach(System.out::println); // 副作用:打印到控制台
// 输出: Alice查询与匹配:检查元素属性
Optional<T> findFirst()Optional<T> findAny()boolean anyMatch(Predicate<? super T> predicate), e.g.
users.stream().anyMatch(user -> user.isAdmin())boolean allMatch(Predicate<? super T> predicate)
归约:将流合并为单个值
比如,计算总和、求最大值、或将所有字符串连接起来等。
long count()Optional<T> max(Comparator<? super T> comparator)Optional<T> reduce(BinaryOperator<T> accumulator)
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
Optional<Integer> sum = numbers.stream().reduce((a, b) -> a + b); // or Integer::sum
sum.ifPresent(System.out::println); // 输出: 15收集:将流元素聚合到容器中
将流中的元素重新组织成另一种形式,通常是一个集合(如List, Set, Map)。语法:<R, A> R collect(Collector<? super T, A, R> collector)。
Set<String> uniqueNames = names.stream().collect(Collectors.toSet());Collectors.toList()Collectors.toMap()
Map<String, Integer> nameToAgeMap = people.stream()
.collect(Collectors.toMap(
p -> p.getName(), // 获取Key
p -> p.getAge() // 获取Value
));Collectors.joining()
String names = people.stream()
.map(Person::getName) // Stream<Person> -> Stream<String>
.collect(Collectors.joining(", "));Collectors.summingDouble()
Double totalElectronicsPrice = products.stream()
.filter(p -> "Electronics".equals(p.getCategory()))
.collect(Collectors.summingDouble(Product::getPrice));Optional类
User user = findUserById("123");
String username = user.getName(); // 如果 user 为 null,这里将抛出 NullPointerExceptionOptional 的诞生正是为了在类型系统层面解决这个问题。
Definition
java.util.Optional<T> 是一个容器对象,它最多可以持有一个非 null 的 T 类型的值。
创建Optional
Optional.of(T value),当你确定 value 绝对不为 null 时使用。如果 value 为 null,它会立即抛出 NullPointerException。
Optional<String> name = Optional.of("John Doe");Optional.ofNullable(T value),当你持有一个可能为 null 的值时使用。如果 value 不为 null,它会创建一个包含该值的 Optional;如果 value 为 null,它会创建一个空的 Optional。
Optional<User> user = Optional.ofNullable(findUserFromDB());Optional.ofNullable(T value),如果 value 不为 null,它会创建一个包含该值的 Optional;如果 value 为 null,它会创建一个空的 Optional。Optional.empty(),创建一个空的 Optional 实例。
使用Optional
ifPresent(Consumer<? super T> consumer)
当你只想在值存在时执行某个操作,可以使用 ifPresent() 方法。
传统方法:
String name = getNullableName();
if (name != null) {
System.out.println("Name is: " + name);
}使用 ifPresen:
Optional.ofNullable(getNullableName()).ifPresent(name -> System.out.println("Name is: " + name));orElse(T other)andorElseGet(Supplier<? extends T> other)
当 Optional 为空时,我们常常需要提供一个默认值。
String name = Optional.ofNullable(getNullableName()).orElse("default");
String name2 = Optional.ofNullable(getNullableName()).orElseGet(() -> createDefaultName());Optional配合map()
Optional<User> userOptional = Optional.ofNullable(getUser());
Optional<String> zipCodeOptional = userOptional
.map(User::getAddress)
.map(Address::getZipCode);
String zipCode = zipCodeOptional.orElse("Not available");以上例子中,map(User::getAddress) 将 Optional<User> 转换为了 Optional<Address>,整个过程无需任何 null 检查。
Optional配合filter()
Optional<String> name = Optional.of("John Doe");
// 只有当名字包含 "John" 时才保留
Optional<String> johnOptional = name.filter(n -> n.contains("John")); // 结果为 Optional["John Doe"]
Optional<String> janeOptional = name.filter(n -> n.contains("Jane")); // 结果为 Optional.emptyJava基础 - Java函数式编程 - Stream API
http://example.com/2025/08/02/JAVA/java-fp-stream/