当lambda表达式传递给方法时,可以使用type-parameters检索其返回类型和参数类型(如果调用者特别指定)。
我不明白的是,如果表达式也使用return-type作为参数类型,java似乎会丢弃lambda表达式的返回类型给出的类型信息。
用文字解释这个问题真的很难。因此,我编写了以下示例代码以进一步说明。
//Case 1
@FunctionalInterface
interface Test<R> {
void returnValue(R takes);
}
static <R> R test(Test<R> test) {
//... Do something with test
}
public static void main(final String[] args) {
test((a) -> System.out.println("called"));
//This call will always return an Object
//This is clear. It is totally unnknow wich type a has at compile-time
}
//--------------------------------------------------------------------------
//Case 2
@FunctionalInterface
interface Test<R> {
R returnValue();
}
static <R> R test(Test<R> test) {
//... Do something with test
}
public static void main(final String[] args) {
test(() -> " ");
//This call will always return a String
//This is clear. R is specified to be a String by the return value.
}
//--------------------------------------------------------------------------
//Case 3
@FunctionalInterface
interface Test<R> {
R returnValue(R takes);
}
static <R> R test(Test<R> test) {
//... Do something with test
}
public static void main(final String[] args) {
test((a) -> " ");
//This call will always return an Object
//This it not clear. R is specified to be a String by the return value
//Why doesn't it return a String ?
}
修改 深入研究这个问题我注意到问题只有在链接调用时才会发生。下面的代码演示了这一点。它是使用java版本1.8.0_73在eclipse中编译的。
package test;
public class TestLambdaGenerics {
@FunctionalInterface
interface Test<R> {
R returnValue(R takes);
}
static <R> Test<R> test(final Test<R> test) {
// ... Do something with test
return test;
}
public static void main(final String[] args) {
final Test<String> t = test((a) -> " ");
// Above works fine
final String t2 = test((a) -> " ").returnValue(" ");
// Above terminates with output:
// Exception in thread "main" java.lang.Error: Unresolved compilation problem:
// Type mismatch: cannot convert from Object to String
//
// at test.TestLambdaGenerics.main(TestLambdaGenerics.java:18)
}
}
编辑2:
问题解决了目前java不支持使用类型推理的“链式调用”。
答案 0 :(得分:0)
我测试了你的例子,如果2/3,returnValue总是有String类。
/*
//Case 1
public class LambdaGenerics {
public static void main(final String[] args) {
System.out.println(test((a) -> System.out.println("called")).getClass());
//This call will always return a Test<Object>
//This is clear. It is totally unknown which type a has at compile-time
}
static <R> Test<R> test(Test<R> test) {
//... Do something with test
return test;
}
}
@FunctionalInterface
interface Test<R> {
void returnValue(R takes);
}
*/
//--------------------------------------------------------------------------
/*
//Case 2
public class LambdaGenerics {
public static void main(final String[] args) {
System.out.println(test(() -> "test").returnValue().getClass());
//This call will always return a Test<Object>
//This is clear. It is totally unknown which type a has at compile-time
}
static <R> Test<R> test(Test<R> test) {
//... Do something with test
return test;
}
}
@FunctionalInterface
interface Test<R> {
R returnValue();
}
*/
//--------------------------------------------------------------------------
/*
//Case 3
public class LambdaGenerics {
public static void main(final String[] args) {
System.out.println(test((a) -> " ").returnValue(test((a) -> " ")).getClass());
//This call will always return a Test<Object>
//This is clear. It is totally unknown which type a has at compile-time
}
static <R> Test<R> test(Test<R> test) {
//... Do something with test
return test;
}
}
@FunctionalInterface
interface Test<R> {
R returnValue(R takes);
}
*/