Java 8 lambdas, Function.identity() 或 t->t

2022-08-31 04:56:53

我有一个关于该方法用法的问题。Function.identity()

想象一下下面的代码:

Arrays.asList("a", "b", "c")
          .stream()
          .map(Function.identity()) // <- This,
          .map(str -> str)          // <- is the same as this.
          .collect(Collectors.toMap(
                       Function.identity(), // <-- And this,
                       str -> str));        // <-- is the same as this.

有什么理由你应该使用而不是(反之亦然)。我认为第二个选项更具可读性(当然是品味问题)。但是,有什么“真正”的理由为什么应该首选一个人吗?Function.identity()str->str


答案 1

从当前的 JRE 实现开始,将始终返回相同的实例,而每次出现的 不仅会创建自己的实例,甚至还会有不同的实现类。有关更多详细信息,请参阅此处Function.identity()identifier -> identifier

原因是编译器生成一个综合方法,其中包含该 lambda 表达式的平凡主体(在 的情况下,等效于 ),并告诉运行时创建调用此方法的功能接口的实现。因此,运行时只看到不同的目标方法,而当前实现不会分析这些方法以确定某些方法是否等效。x->xreturn identifier;

因此,使用而不是可能会节省一些内存,但如果您真的认为这比更具可读性,则不应该推动您的决定。Function.identity()x -> xx -> xFunction.identity()

您还可以考虑在启用调试信息的情况下进行编译时,综合方法将具有指向保存 lambda 表达式的源代码行的行调试属性,因此您有机会在调试时找到特定实例的源。相反,在调试操作期间遇到 返回的实例时,您将不知道谁调用了该方法并将该实例传递给该操作。FunctionFunction.identity()


答案 2

在您的示例中,两者之间没有太大的区别,因为内部它只是 。str -> strFunction.identity()t->t

但有时我们不能使用,因为我们不能使用.看看这里:Function.identityFunction

List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);

这将编译良好

int[] arrayOK = list.stream().mapToInt(i -> i).toArray();

但是如果你尝试编译

int[] arrayProblem = list.stream().mapToInt(Function.identity()).toArray();

你会得到编译错误,因为期望,这与 无关。也没有方法。mapToIntToIntFunctionFunctionToIntFunctionidentity()


推荐