为了账号安全,请及时绑定邮箱和手机立即绑定

为什么编译时不检查 lambda 返回类型?

为什么编译时不检查 lambda 返回类型?

扬帆大鱼 2023-10-13 10:09:35
使用的方法引用具有返回类型Integer。String但在下面的示例中,不兼容是允许的。如何修复方法with声明以获得方法引用类型安全而无需手动转换?import java.util.function.Function;public class MinimalExample {  static public class Builder<T> {    final Class<T> clazz;    Builder(Class<T> clazz) {      this.clazz = clazz;    }    static <T> Builder<T> of(Class<T> clazz) {      return new Builder<T>(clazz);    }    <R> Builder<T> with(Function<T, R> getter, R returnValue) {      return null; //TODO    }  }  static public interface MyInterface {    Integer getLength();  }  public static void main(String[] args) {// missing compiletimecheck is inaceptable:    Builder.of(MyInterface.class).with(MyInterface::getLength, "I am NOT an Integer");// compile time error OK:     Builder.of(MyInterface.class).with((Function<MyInterface, Integer> )MyInterface::getLength, "I am NOT an Integer");// The method with(Function<MinimalExample.MyInterface,R>, R) in the type MinimalExample.Builder<MinimalExample.MyInterface> is not applicable for the arguments (Function<MinimalExample.MyInterface,Integer>, String)  }}
查看完整描述

4 回答

?
子衿沉夜

TA贡献1828条经验 获得超3个赞

在第一个示例中,和MyInterface::getLength分别帮助"I am NOT an Integer"解析通用参数T和。RMyInterfaceSerializable & Comparable<? extends Serializable & Comparable<?>>


// it compiles since String is a Serializable

Function<MyInterface, Serializable> function = MyInterface::getLength;

Builder.of(MyInterface.class).with(function, "I am NOT an Integer");

MyInterface::getLength并不总是 a ,Function<MyInterface, Integer>除非您明确这么说,这会导致编译时错误,如第二个示例所示。


// it doesn't compile since String isn't an Integer

Function<MyInterface, Integer> function = MyInterface::getLength;

Builder.of(MyInterface.class).with(function, "I am NOT an Integer");


查看完整回答
反对 回复 2023-10-13
?
翻过高山走不出你

TA贡献1875条经验 获得超3个赞

类型推断在这里发挥了作用。R考虑方法签名中的泛型:

<R> Builder<T> with(Function<T, R> getter, R returnValue)

在所列情况中:

Builder.of(MyInterface.class).with(MyInterface::getLength, "I am NOT an Integer");

的类型R被成功推断为

Serializable, Comparable<? extends Serializable & Comparable<?>>

并且 aString确实通过这种类型暗示,因此编译成功。


要显式指定 的类型R并找出不兼容性,只需将代码行更改为:

Builder.of(MyInterface.class).<Integer>with(MyInterface::getLength, "not valid");


查看完整回答
反对 回复 2023-10-13
?
紫衣仙女

TA贡献1839条经验 获得超15个赞

这是因为你的泛型类型参数R可以被推断为 Object,即以下编译:

Builder.of(MyInterface.class).with((Function<MyInterface, Object>) MyInterface::getLength, "I am NOT an Integer");


查看完整回答
反对 回复 2023-10-13
?
梦里花落0921

TA贡献1772条经验 获得超6个赞

这个答案基于其他答案,这些答案解释了为什么它不能按预期工作。


解决方案

下面的代码通过将双函数“with”拆分为两个连贯函数“with”和“returning”来解决该问题:


class Builder<T> {

...

class BuilderMethod<R> {

  final Function<T, R> getter;


  BuilderMethod(Function<T, R> getter) {

    this.getter = getter;

  }


  Builder<T> returning(R returnValue) {

    return Builder.this.with(getter, returnValue);

  }

}


<R> BuilderMethod<R> with(Function<T, R> getter) {

  return new BuilderMethod<>(getter);

}

...

}


MyInterface z = Builder.of(MyInterface.class).with(MyInterface::getLength).returning(1L).with(MyInterface::getNullLength).returning(null).build();

System.out.println("length:" + z.getLength());


// YIPPIE COMPILATION ERRROR:

// The method returning(Long) in the type BuilderExample.Builder<BuilderExample.MyInterface>.BuilderMethod<Long> is not applicable for the arguments (String)

MyInterface zz = Builder.of(MyInterface.class).with(MyInterface::getLength).returning("NOT A NUMBER").build();

System.out.println("length:" + zz.getLength());

(有点陌生)


查看完整回答
反对 回复 2023-10-13
  • 4 回答
  • 0 关注
  • 119 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信