【问题标题】:Lambda and Generics: Why Does This Compile?Lambda 和泛型:为什么要编译?
【发布时间】:2016-08-08 06:58:22
【问题描述】:

这是我的代码的简化示例以证明我的观点:

public class Tmp {

  static class X {
    void setStr(String blah) {
    }
    String getStr() {
      return null;
    }
  }

  public void test() {
    createCheck(X::getStr, "");   // supposed to compile
    createCheck(X::getStr, 123);  // rather not: int isn't String
  }

  private <T, V> BiPredicate<T, String> createCheck(Function<T, V> func, V value) {
    return new BiPredicate<T, String>() {

      @Override
      public boolean test(T t, String ref) {
        assertThat(func.apply(t))
            .as(ref)
            .isEqualTo(value);
        return true;
      }

    };
  }

}

恕我直言,编译器应该看到 createCheck() 中的 V 应该是来自 getter 函数的 String,这就是它应该抱怨 int 的原因。或者反过来。

那么为什么会编译呢?

【问题讨论】:

    标签: java generics lambda


    【解决方案1】:

    您的签名是:

    private <T, V> BiPredicate<T, String> createCheck(Function<T, V> func, V value) {
    

    TV 没有界限,因此绝对可以编译 TV 的任何值。

    返回 BiPredicate&lt;T, String&gt; 但是,isEqualTo 方法采用 String ref 并将其相等性与 Object value 进行比较 - 这也是完全合法的,因为我认为 isEqualTo采用Object 来模仿Object.equals 的行为。


    在你的例子中:

    createCheck(X::getStr, 123);
    

    V 只是Object,因为这是可以应用于StringInteger 的最严格的类型绑定。


    你是不是想说:

    private <T> BiPredicate<T, String> createCheck(Function<T, String> func, String value) {
    

    【讨论】:

    • 嗯,“意思”,是的。但是,我必须为每种类型编写一个方法,我想将其传递为value。这不是我的本意……
    • 我可以看到您正在尝试做什么@sjngm,但我看不到安全的方法。您可以尝试&lt;T, V&gt; BiPredicate&lt;T, V&gt; createCheck(Function&lt;T, V&gt; func, V value) - 但这显然与您原来的方法有不同的回报。在第二种情况下,这将导致BiPredicate&lt;X, Object&gt;;它可能会导致您正在寻找的编译错误...
    • 不,BiPredicate&lt;T, V&gt; 影响到test() 的参数。
    • 完全正确 - 目前您有一些 V 类型的值和一些将该值从类型 T 映射到类型 V 的映射器。然后你有一个BiPredicate 接受一个V,把它变成一个T,然后将它与一个任意的String 进行比较。这没有多大意义......
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-20
    • 2016-04-05
    • 1970-01-01
    • 1970-01-01
    • 2020-06-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多