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

我有一个关于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 (反之亦然)。 我认为第二个选项更具可读性(当然是品味)。 但是,有什么“真正的”理由为什么应该被优先考虑呢?

就目前的JRE实现而言, Function.identity()将始终返回相同的实例,而identifier -> identifier每次出现不仅会创build自己的实例,甚至还会有一个独特的实现类。 有关更多细节,请参阅此处 。

原因是编译器生成一个保存该lambdaexpression式的普通主体的合成方法(在x->x的情况下,等价于return identifier; ),并且指示运行时创build调用此方法的函数接口的实现。 所以运行时只能看到不同的目标方法,而目前的实现并不能分析方法来找出某些方法是否等价。

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

您也可以考虑,在启用debugging信息的情况下进行编译时,合成方法将具有指向包含lambdaexpression式的源代码行的行debugging属性,因此您可以find特定Function实例的源代码debugging。 相反,在debugging操作期间遇到由Function.identity()返回的实例时,您将不知道是谁调用了该方法并将该实例传递给该操作。

在你的例子中, str -> strFunction.identity()之间没有很大的区别,因为它在内部只是t->t

但有时我们不能使用Function.identity 。 看看这里

 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(); 

你将得到编译错误,因为mapToInt需要ToIntFunction ,它与Function无关。 ToIntFunction也没有identity()方法。

来自JDK源 :

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

所以,不,只要它在语法上是正确的。