ZetCode

Java Function.identity 方法

最后修改时间:2025 年 4 月 16 日

Function.identity 方法是 Java 的 java.util.function.Function 接口中的一个静态工具方法。它返回一个始终返回其输入参数且不作任何修改的函数。这在需要函数但不需要任何转换的函数式编程场景中非常有用。

恒等函数在处理 Java 流和收集器时特别有价值。当一个操作需要一个函数参数,但您希望保留原始值时,它们用作占位符。该方法作为函数式编程增强的一部分在 Java 8 中引入。

Function.identity 基础知识

identity 方法被定义为 Function 接口中的一个静态方法。它返回一个实现恒等操作的函数 - 输出等于输入。该方法的签名简单明了。

static <T> Function<T, T> identity() {
    return t -> t;
}

实现只是简单地返回一个 lambda 表达式,该表达式接受一个输入并原样返回。泛型类型参数确保类型安全,同时保持灵活性。这使得它可以在各种上下文中使用。

简单的恒等函数示例

这个基本示例演示了如何创建和使用恒等函数。我们将展示直接用法以及它与执行相同操作的自定义 lambda 的比较。

Main.java
package com.zetcode;

import java.util.function.Function;

public class Main {

    public static void main(String[] args) {

        // Create identity function
        Function<String, String> identity = Function.identity();
        
        // Apply the function
        String input = "Hello, World!";
        String output = identity.apply(input);
        
        System.out.println("Input: " + input);
        System.out.println("Output: " + output);
        System.out.println("Same object? " + (input == output));
        
        // Equivalent lambda expression
        Function<String, String> customIdentity = s -> s;
        System.out.println("Custom identity: " + customIdentity.apply("Test"));
    }
}

此示例表明恒等函数返回它接收到的内容。输出演示了它与相同的对象引用相同。自定义 lambda 版本展示了 identity 实际上在后台做了什么。

流操作中的恒等

Function.identity 的一个常见用例是在流操作中,特别是与收集器一起使用。当您需要将值用作映射中的键而无需转换时,恒等函数是完美的选择。

Main.java
package com.zetcode;

import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Main {

    public static void main(String[] args) {

        // Create a stream of strings
        Stream<String> words = Stream.of("apple", "banana", "cherry");
        
        // Use identity in toMap collector
        Map<String, Integer> wordLengths = words.collect(
            Collectors.toMap(
                Function.identity(),  // Use the word itself as key
                String::length       // Use word length as value
            )
        );
        
        System.out.println("Word lengths: " + wordLengths);
        
        // Alternative without identity (more verbose)
        List<String> fruits = List.of("orange", "pear", "kiwi");
        Map<String, Integer> altMap = fruits.stream()
            .collect(Collectors.toMap(
                fruit -> fruit,     // Equivalent to identity
                String::length
            ));
            
        System.out.println("Alternative map: " + altMap);
    }
}

此示例演示了 Function.identity 如何提供比在流收集器中编写 fruit -> fruit 更简洁的替代方案。它使代码更具可读性,并更清晰地表达意图。

分组操作中的恒等

Function.identity 的另一个强大用法是与分组收集器一起使用。当您需要按元素本身进行分组时,恒等函数提供了一个优雅的解决方案。

Main.java
package com.zetcode;

import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

public class Main {

    public static void main(String[] args) {

        List<String> words = List.of("apple", "banana", "apple", 
                                   "orange", "banana", "apple");
        
        // Count word occurrences using identity
        Map<String, Long> wordCounts = words.stream()
            .collect(Collectors.groupingBy(
                Function.identity(),
                Collectors.counting()
            ));
            
        System.out.println("Word counts: " + wordCounts);
        
        // Group strings by their identity
        Map<String, List<String>> grouped = words.stream()
            .collect(Collectors.groupingBy(Function.identity()));
            
        System.out.println("Grouped words: " + grouped);
    }
}

在这里,我们看到 Function.identity 用于按元素本身进行分组。第一个收集器计算每个单词的出现次数,而第二个收集器将相同的字符串分组在一起。两者都演示了使用恒等函数的简洁、富有表现力的代码。

恒等函数与函数组合

Function.identity 在函数组合场景中很有用。它充当一个不影响组合链的**中性元素**。

Main.java
package com.zetcode;

import java.util.function.Function;

public class Main {

    public static void main(String[] args) {

        // Create some transformation functions
        Function<String, String> toUpper = String::toUpperCase;
        Function<String, String> addExclamation = s -> s + "!";
        
        // Create identity function
        Function<String, String> identity = Function.identity();
        
        // Compose with identity (no effect)
        Function<String, String> composed1 = identity.andThen(toUpper);
        Function<String, String> composed2 = addExclamation.compose(identity);
        
        System.out.println("Composed1: " + composed1.apply("hello"));
        System.out.println("Composed2: " + composed2.apply("world"));
        
        // More complex composition
        Function<String, String> pipeline = identity
            .andThen(toUpper)
            .andThen(addExclamation)
            .andThen(identity);
            
        System.out.println("Pipeline result: " + pipeline.apply("java"));
    }
}

此示例展示了如何在不影响结果的情况下在函数组合中使用 Function.identity。它充当组合链中的中性元素,类似于 0 在加法中或 1 在乘法中的作用。

恒等函数在方法引用上下文中的应用

Function.identity 经常与方法引用进行比较。虽然在某些情况下相似,但它们服务于不同的目的。此示例阐明了何时使用每种方法。

Main.java
package com.zetcode;

import java.util.function.Function;
import java.util.stream.Stream;

public class Main {

    public static void main(String[] args) {

        // Using identity in map operation
        Stream.of("one", "two", "three")
            .map(Function.identity())
            .forEach(System.out::println);
        
        // Equivalent using method reference
        Stream.of("uno", "dos", "tres")
            .map(s -> s)
            .forEach(System.out::println);
            
        // When method reference differs
        class Wrapper {
            private final String value;
            
            Wrapper(String value) { this.value = value; }
            
            String getValue() { return value; }
        }
        
        // Correct: method reference to getter
        Stream.of(new Wrapper("a"), new Wrapper("b"))
            .map(Wrapper::getValue)
            .forEach(System.out::println);
            
        // Incorrect: identity would return Wrapper objects
        Stream.of(new Wrapper("x"), new Wrapper("y"))
            .map(Function.identity())
            .forEach(w -> System.out.println(w.getValue()));
    }
}

此示例演示了 Function.identity 和方法引用之间的区别。虽然它们可能看起来相似,但恒等函数始终原样返回其输入,而方法引用可以通过调用对象上的方法来转换对象。

高级流处理中的恒等

对于更复杂的流处理场景,将 Function.identity 与其他流操作结合使用可以帮助保持代码的清晰度。这是一个高级示例。

Main.java
package com.zetcode;

import java.util.Arrays;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

public class Main {

    public static void main(String[] args) {

        String[] colors = {"red", "green", "blue", "red", "green", "yellow"};
        
        // Advanced processing: count, filter, and map
        Map<String, Long> frequentColors = Arrays.stream(colors)
            .collect(Collectors.groupingBy(
                Function.identity(),
                Collectors.counting()
            ))
            .entrySet().stream()
            .filter(e -> e.getValue() > 1)
            .collect(Collectors.toMap(
                Map.Entry::getKey,
                e -> e.getValue() * 10  // Transform count
            ));
            
        System.out.println("Processed colors: " + frequentColors);
        
        // Another example: processing with identity
        Map<Boolean, Map<String, Long>> partitioned = Arrays.stream(colors)
            .collect(Collectors.partitioningBy(
                s -> s.length() > 3,
                Collectors.groupingBy(
                    Function.identity(),
                    Collectors.counting()
                )
            ));
            
        System.out.println("Partitioned counts: " + partitioned);
    }
}

这个高级示例展示了 Function.identity 在复杂的流处理中的应用。它在更大的流管道中的分组操作中使用。恒等函数有助于专注于重要的转换,同时透明地处理分组键。

来源

Java Function.identity 文档

Function.identity 方法是 Java 函数式编程工具包中一个简单但强大的工具。在处理流和函数组合时,它会促进更简洁的代码。了解其正确用法可以使您的 Java 代码更具表现力和可维护性。

作者

我的名字是 Jan Bodnar,我是一位经验丰富的程序员,在该领域拥有多年的经验。我于 2007 年开始撰写编程文章,此后撰写了 1,400 多篇文章和八本电子书。凭借超过八年的教学经验,我致力于分享我的知识并帮助他人掌握编程概念。

列出所有Java教程