代码之家  ›  专栏  ›  技术社区  ›  salezica

Java方法引用是否稳定?[复制品]

  •  23
  • salezica  · 技术社区  · 6 年前

    如果使用新语法获取方法引用:

    anObject::aMethod
    

    我总是得到同样的东西吗?也就是说,我能相信对同一方法的两个引用是相等的吗?

    很高兴知道,例如,我是否打算将它们用作 Runnable 可以添加和删除的回调:

    someLibrary.addCallback(anObject::aMethod)
    // later
    someLibrary.removeCallback(sameObject::sameMethod)
    

    这需要将引用保存在 可运行的 保持稳定的变量?

    2 回复  |  直到 6 年前
        1
  •  17
  •   Misha    6 年前

    JLS makes no promises 关于从方法引用表达式中得到的内容的同一性或相等性。

    您可以运行快速测试:

    Object obj = new Object();
    
    IntSupplier foo = obj::hashCode;
    IntSupplier bar = obj::hashCode;
    
    System.out.println(foo == bar);  // false
    
    System.out.println(foo.equals(bar));  // false      
    

    但这当然取决于实现。

    能够 做你的羔羊 Serializable 并用serliaized表示法为回调映射设置键。见 How to serialize a lambda? . 虽然这是可行的,但并不是规范要求的。

        2
  •  7
  •   QuentinC    6 年前

    试试这个就知道答案:

    Object object = ...;
    Supplier<String> s1 = object::toString;
    Supplier<String> s2 = object::toString;
    System.out.println(s1.equals(s2));
    

    答案是…不幸的是没有。

    当然,如果您保持相同的引用(即,相同的对象),它将起作用;但是,如上例所示,如果您请求两个lambda,尽管它们看起来是相同的,但它们永远不会相等。 因此 reference = object::method 后来 remove(reference) 很明显会起作用,但是 remove(sameObject::sameMethod) 从一个集合中,如果它是这样写的文字永远不会工作。

    对于构造函数(例如arraylist::new)和未绑定方法(例如object::tostring),答案也是否定的。似乎每次使用lambda表达式时都会构造一个新的lambda。

    正如@hitobat所指出的那样,如果你想一想lambdas到底是什么以及它们是从哪里来的,那么这种不好的品质是有意义的。基本上, Supplier<String> x = myObject::toString 是用于 Supplier<String> x = new Supplier<String>( ... ) . 如果没有适当的object.equals重载,匿名类的两个实例显然是不同的。可能和很多人一样,我认为在某个地方有一种经常使用的lambdas缓存,以提高效率;嗯,一点也不。