Java Streams 中的 Identity 函数
最后修改于 2025 年 5 月 25 日
Identity 函数是函数式编程中的一个基本概念,在 Java Stream 操作中扮演着重要的角色。本教程解释了它的目的并演示了实际的用例。
Function.identity 是 Java 的 java.util.function.Function 接口中的一个静态方法,它返回一个始终返回其输入参数的函数。它本质上是一个空操作(no-op)函数,在需要函数参数但不需要转换的各种 stream 操作中非常有用。
Identity 函数在 Stream 操作(如 map 和 collect)中特别有用,当你需要传递一个函数但又不想修改元素时。它提供了一种清晰、可读的方式来表达函数式管道中的“无转换”。
基本 Identity 函数用法
此示例演示了在 stream 管道中 Function.identity 的最简单用法。
void main() {
Stream.of("apple", "banana", "cherry")
.map(Function.identity())
// .map(e -> e)
.forEach(System.out::println);
}
在这里,我们使用 Function.identity 作为映射函数,这导致 stream 元素没有任何更改。虽然此示例没有转换数据,但它显示了 identity 函数的基本语法和行为。
Function.identity 的语法等同于使用 e -> e lambda 表达式,但是使用 Function.identity 更简洁和表达力更强。
$ java Main.java apple banana cherry
Collectors.toMap 中的 Identity
Function.identity 最常见的用途之一是与 Collectors.toMap 一起使用,当你希望将 stream 元素用作 map 键时。
void main() {
List<String> fruits = List.of("apple", "banana", "cherry");
Map<String, Integer> fruitMap = fruits.stream()
.collect(Collectors.toMap(
Function.identity(), // Use the string as key
String::length // Use length as value
));
System.out.println(fruitMap);
}
在此示例中,我们创建了一个 map,其中键是水果名称(由于 Function.identity 的作用,没有更改),值是水果名称的长度。Identity 函数清楚地表明我们正在使用原始元素作为键。
$ java Main.java
{banana=6, apple=5, cherry=6}
Identity 与 Lambda 表达式
此示例将使用 Function.identity 与等效的 lambda 表达式进行比较,以演示它们的等效性。
void main() {
// Using Function.identity()
Stream.of(1, 2, 3)
.map(Function.identity())
.forEach(System.out::println);
// Using equivalent lambda Stream.of(1, 2, 3).map(x -> x)
//.forEach(System.out::println);
}
这两个版本产生相同的结果。通常首选 Function.identity,因为它更明确地表达了意图,并且在某些情况下可能具有轻微的性能优势,因为它是一个单例函数。
$ java Main.java 1 2 3 1 2 3
GroupingBy 中的 Identity
当你想要按元素本身进行分组时,Identity 函数通常与 Collectors.groupingBy 一起使用。
void main() {
List<String> words = List.of("one", "two", "three", "one", "three");
Map<String, Long> counts = words.stream()
.collect(Collectors.groupingBy(
Function.identity(),
Collectors.counting()
));
System.out.println(counts);
}
在这里,我们使用 Function.identity 作为分组的分类器函数,这意味着我们按实际的字符串值进行分组。 这会生成列表中每个单词的频率计数。
$ java Main.java
{one=2, two=1, three=2}
带有 Optional 的 Identity
在 stream 操作中使用 Optional 时,Identity 函数可能很有用。
void main() {
List<Optional<String>> optionals = List.of(
Optional.of("🍎 Apple"),
Optional.empty(),
Optional.of("🍌 Banana"),
Optional.of("🍒 Cherry"),
Optional.empty(),
Optional.of("🍍 Pineapple"));
// Extract present values without transformation
List<String> values = optionals.stream()
.flatMap(opt -> opt.map(Function.identity()).stream())
.collect(Collectors.toList());
System.out.println(values);
}
此示例演示了使用 Function.identity 来处理 Optional 值的 stream,在不转换它们的情况下提取存在的值。
$ java Main.java [🍎 Apple, 🍌 Banana, 🍒 Cherry, 🍍 Pineapple]
来源
Identity 函数是 Java Streams 中一个简单但功能强大的工具,它清楚地表达了函数式管道中“无转换”的意图。 虽然它不修改数据,但它在需要函数参数的 stream 操作中起着重要的作用。
作者
列出所有Java教程。