为什么java传递lambda表达式时将type-argument设置为object,其类型为parameter-和return-type?

时间:2016-03-25 14:32:28

标签: java lambda type-parameter

当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不支持使用类型推理的“链式调用”。

请参阅:this questionthis article

1 个答案:

答案 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);
}
*/