正在寻找编译器生成的lambda文档,以便在Java8中将专用函数对象转换为通用函数对象
我已经使用Java8Lambdas几个月了,刚刚发现了一个行为,我不记得在Java文档或编程网站上看到过任何提及。可以在以下代码中看到:正在寻找编译器生成的lambda文档,以便在Java8中将专用函数对象转换为通用函数对象,java,lambda,autoboxing,functional-interface,unboxing,Java,Lambda,Autoboxing,Functional Interface,Unboxing,我已经使用Java8Lambdas几个月了,刚刚发现了一个行为,我不记得在Java文档或编程网站上看到过任何提及。可以在以下代码中看到: public class CompilerGeneratedLambdaExample { static <A,R> R callFunction(Function<A,R> function, A arg) { return function.apply(arg); } static int
public class CompilerGeneratedLambdaExample
{
static <A,R> R callFunction(Function<A,R> function, A arg) {
return function.apply(arg);
}
static int staticFunction_arg_int_return_int(int i) {
return i;
}
public static void main(String [] args) {
/* (A) This compiles and executes as expected - stack looks like:
*
Thread [main] (Suspended (breakpoint at line 16 in CompilerGeneratedLambdaExample))
CompilerGeneratedLambdaExample.staticFunction_arg_int_return_int(int) line: 16
1268650975.apply(Object) line: not available
CompilerGeneratedLambdaExample.callFunction(Function<A,R>, A) line: 11
CompilerGeneratedLambdaExample.main(String[]) line: 33
*/
Object value = callFunction(CompilerGeneratedLambdaExample::staticFunction_arg_int_return_int,new Integer(10));
System.out.println("value type: " + value.getClass().getName());
System.out.println("value: " + value);
/* (B) This will not compile- error message is:
*
The method callFunction(Function<A,R>, A) in the type CompilerGeneratedLambdaExample is not applicable for the arguments (IntUnaryOperator, Integer)
*/
IntUnaryOperator specializedFunction = CompilerGeneratedLambdaExample::staticFunction_arg_int_return_int; // OK
//Object value = callFunction(specializedFunction,new Integer(10)); // produces compiler error quoted above
}
}
这些评论基于我在Java1.8遵从性级别上看到的最新版本的EclipseJava编译器。我对情况的总结如下:
A如果将专用类型的函数对象作为方法引用传递给需要该类型的泛型对应项的函数,编译器将包装处理参数和返回值转换的对象
但是如果您首先将方法引用分配给专用类型的变量,并尝试将该变量传递给期望泛型类型的函数,则会出现一个编译器错误,指示类型不匹配
行为A为特殊函数类型的方法引用提供了自动装箱和取消装箱的等价物,对于我正在做的工作非常有用。如果行为B起作用,它也会很有用,但事实上它似乎与Java对象类型系统的一般工作方式不一致
我的问题是——Java文档中处理的这两种行为——特别是为函数类型的方法引用提供自动装箱和取消装箱等价物的行为A——在哪里,网络上还有哪些关于它们的有用讨论?问题是您被指派给IntUnaryOperator,这不是一项功能。你可以
Object value2 = callFunction(
CompilerGeneratedLambdaExample::staticFunction_arg_int_return_int,
new Integer(10));
或
或者使用自动装箱
Function<Integer, Object> specializedFunction =
CompilerGeneratedLambdaExample::staticFunction_arg_int_return_int;
Object value2 = callFunction(specializedFunction, 10);
有关文档,请参见谢谢Elliott的评论。我将方法引用指定给IntUnaryOperator类型的变量的原因是,它与方法staticFunction_arg_int_return_int的签名完全匹配,即int->int。我不想修复它,只是将它作为Java工作方式的数据点来表示。但是你的替代任务提供了另一个数据点,这是一个非常有价值的数据点 如果我将此代码C添加到main:
/* (C) genericForSpecializedFunction - works - stacktrace:
*
Thread [main] (Suspended (breakpoint at line 15 in CompilerGeneratedLambdaExample))
CompilerGeneratedLambdaExample.staticFunction_arg_int_return_int(int) line: 15
575593575.apply(Object) line: not available <- lambda
CompilerGeneratedLambdaExample.callFunction(Function<A,R>, A) line: 10
CompilerGeneratedLambdaExample.main(String[]) line: 67
Output:
genericForSpecializedFunction: testHelp.CompilerGeneratedLambdaExample$$Lambda$2/575593575@14acaea5 <- same lambda
(C) value type: java.lang.Integer
(C) value: 10
*/
Function<Integer,Integer> genericForSpecializedFunction = CompilerGeneratedLambdaExample::staticFunction_arg_int_return_int; // OK
System.out.println("genericForSpecializedFunction: " + genericForSpecializedFunction);
Object value3 = callFunction(genericForSpecializedFunction,new Integer(10));
System.out.println("(C) value type: " + value3.getClass().getName());
System.out.println("(C) value: " + value3)
我看到静态方法staticFunction_arg_int_return_int被包装在lambda中,就像直接传递给callFunction时一样。实际上,两种情况下都发生了相同的转换(如果你想这么说的话)
此外,如果我添加代码D类似于toC,仅使用直接匹配非专用类型的静态方法:
<code>
static Integer staticFunction_arg_Integer_return_Integer(Integer i) {
return i;
}
...
/* (D) with generic methods - stack
*
Thread [main] (Suspended (breakpoint at line 19 in CompilerGeneratedLambdaExample))
CompilerGeneratedLambdaExample.staticFunction_arg_Integer_return_Integer(Integer) line: 19
226710952.apply(Object) line: not available <- lambda
CompilerGeneratedLambdaExample.callFunction(Function<A,R>, A) line: 10
CompilerGeneratedLambdaExample.main(String[]) line: 84
Output:
genericFunction: testHelp.CompilerGeneratedLambdaExample$$Lambda$3/226710952@59fa1d9b <- same lambda
(D) value type: java.lang.Integer
(D) value: 10
*/
Function<Integer,Integer> genericFunction = CompilerGeneratedLambdaExample::staticFunction_arg_Integer_return_Integer; // OK
System.out.println("genericFunction: " + genericFunction);
Object value4 = callFunction(genericFunction,new Integer(10));
System.out.println("(D) value type: " + value4.getClass().getName());
System.out.println("(D) value: " + value4);
</code>
<code>
static int callIntUnaryOperator(IntUnaryOperator function, int arg) {
return function.applyAsInt(arg);
}
...
/* (E) specialiedForGenericFunction - stack
*
Thread [main] (Suspended (breakpoint at line 24 in CompilerGeneratedLambdaExample))
CompilerGeneratedLambdaExample.staticFunction_arg_Integer_return_Integer(Integer) line: 24
684874119.applyAsInt(int) line: not available <- lambda
CompilerGeneratedLambdaExample.callIntUnaryOperator(IntUnaryOperator, int) line: 15
CompilerGeneratedLambdaExample.main(String[]) line: 109
output:
specializedForgenericFunction: testHelp.CompilerGeneratedLambdaExample$$Lambda$4/684874119@4501b7af <- same lambda
*/
IntUnaryOperator specializedForGenericFunction = CompilerGeneratedLambdaExample::staticFunction_arg_Integer_return_Integer; // OK
System.out.println("specializedForgenericFunction: " + specializedForGenericFunction);
int value5 = callIntUnaryOperator(specializedForGenericFunction,10);
//System.out.println("(E) value type: " + value5.getClass().getName());
System.out.println("(E) value: " + value5);
</code>
我看到了与C完全相同的行为,即使不需要参数或返回值转换
最后,如果我添加代码E,通过将泛型函数分配给专用类型来反转场景:
<code>
static Integer staticFunction_arg_Integer_return_Integer(Integer i) {
return i;
}
...
/* (D) with generic methods - stack
*
Thread [main] (Suspended (breakpoint at line 19 in CompilerGeneratedLambdaExample))
CompilerGeneratedLambdaExample.staticFunction_arg_Integer_return_Integer(Integer) line: 19
226710952.apply(Object) line: not available <- lambda
CompilerGeneratedLambdaExample.callFunction(Function<A,R>, A) line: 10
CompilerGeneratedLambdaExample.main(String[]) line: 84
Output:
genericFunction: testHelp.CompilerGeneratedLambdaExample$$Lambda$3/226710952@59fa1d9b <- same lambda
(D) value type: java.lang.Integer
(D) value: 10
*/
Function<Integer,Integer> genericFunction = CompilerGeneratedLambdaExample::staticFunction_arg_Integer_return_Integer; // OK
System.out.println("genericFunction: " + genericFunction);
Object value4 = callFunction(genericFunction,new Integer(10));
System.out.println("(D) value type: " + value4.getClass().getName());
System.out.println("(D) value: " + value4);
</code>
<code>
static int callIntUnaryOperator(IntUnaryOperator function, int arg) {
return function.applyAsInt(arg);
}
...
/* (E) specialiedForGenericFunction - stack
*
Thread [main] (Suspended (breakpoint at line 24 in CompilerGeneratedLambdaExample))
CompilerGeneratedLambdaExample.staticFunction_arg_Integer_return_Integer(Integer) line: 24
684874119.applyAsInt(int) line: not available <- lambda
CompilerGeneratedLambdaExample.callIntUnaryOperator(IntUnaryOperator, int) line: 15
CompilerGeneratedLambdaExample.main(String[]) line: 109
output:
specializedForgenericFunction: testHelp.CompilerGeneratedLambdaExample$$Lambda$4/684874119@4501b7af <- same lambda
*/
IntUnaryOperator specializedForGenericFunction = CompilerGeneratedLambdaExample::staticFunction_arg_Integer_return_Integer; // OK
System.out.println("specializedForgenericFunction: " + specializedForGenericFunction);
int value5 = callIntUnaryOperator(specializedForGenericFunction,10);
//System.out.println("(E) value type: " + value5.getClass().getName());
System.out.println("(E) value: " + value5);
</code>
一切都和C和D一样工作
我对这一切的解释是:
1方法引用的函数类型不是方法引用的固有类型,也不是完全由被引用的方法加上或减去非静态方法的类实例决定的。只有当方法引用被分配给变量、函数参数或返回值时,函数类型才会变得固定,并且函数类型与所引用的方法加或减实例的类型兼容。如果我理解正确,所讨论的功能类型被称为目标类型
2目标类型与被引用方法加或减实例的类型兼容但不相同的一个重要情况是,在原语unbox、specialized和相应对象实例化generic、box之间,某些参数和/或返回值的类型不同
3在这种情况下,对象泛型的特权不超过原语专用类型。它们之间的关系是对称的,因此底层方法可能有(比如)原语arg和函数类型object arg,反之亦然,返回值也是如此。这意味着装箱和拆箱可以走任何一条路
4我最初认为,示例代码中stacktraces和打印的函数对象值中出现的lambda是围绕用于执行参数和返回值类型转换(特别是装箱和拆箱)的底层方法的包装,但我现在认为它们只是方法引用的函数类型的具体实现,由变量类型、函数参数或它们被分配到的返回类型(目标类型)决定。这些具体的实现将始终被创建,并且仅作为偶尔的副作用执行装箱和拆箱转换。实际上,方法引用是编译成lambda对象的源代码实体,就像源代码lambda表达式一样
我将查看您链接到的文档部分,特别注意对目标类型和方法引用的引用 谢谢你,艾略特。我对你通讯的回应 ent太长了,无法作为评论发布,所以我将其作为答案发布——在我看来,这是一个答案,但我对进一步的见解和对Java文档的引用感兴趣,特别是对方法引用的引用。