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教程。