假设我有一个使用lambda表达式(闭包)定义的对象列表。有没有办法检查它们以便进行比较?
我最感兴趣的代码是
List<Strategy> strategies = getStrategies();
Strategy a = (Strategy) this::a;
if (strategies.contains(a)) { // ...
完整的代码是
import java.util.Arrays;
import java.util.List;
public class ClosureEqualsMain {
interface Strategy {
void invoke(/*args*/);
default boolean equals(Object o) { // doesn't compile
return Closures.equals(this, o);
}
}
public void a() { }
public void b() { }
public void c() { }
public List<Strategy> getStrategies() {
return Arrays.asList(this::a, this::b, this::c);
}
private void testStrategies() {
List<Strategy> strategies = getStrategies();
System.out.println(strategies);
Strategy a = (Strategy) this::a;
// prints false
System.out.println("strategies.contains(this::a) is " + strategies.contains(a));
}
public static void main(String... ignored) {
new ClosureEqualsMain().testStrategies();
}
enum Closures {;
public static <Closure> boolean equals(Closure c1, Closure c2) {
// This doesn't compare the contents
// like others immutables e.g. String
return c1.equals(c2);
}
public static <Closure> int hashCode(Closure c) {
return // a hashCode which can detect duplicates for a Set<Strategy>
}
public static <Closure> String asString(Closure c) {
return // something better than Object.toString();
}
}
public String toString() {
return "my-ClosureEqualsMain";
}
}
看来唯一的解决方案是将每个lambda定义为一个字段,并仅使用这些字段。如果要打印调用的方法,最好使用method
。使用lambda表达式有更好的方法吗?
此外,是否可以打印一个lambda并获得一些人类可读的内容?如果您打印this::a
而不是
ClosureEqualsMain$$Lambda$1/821270929@3f99bd52
得到类似于
ClosureEqualsMain.a()
甚至可以使用这个。toString
和方法。
my-ClosureEqualsMain.a();
我不认为有可能从闭包中得到这些信息。闭包不提供状态。
但是你可以使用Java反射,如果你想检查和比较的方法。当然,这不是一个非常漂亮的解决方案,因为性能和异常,这是要抓住的。但是这样你就可以得到那些元信息。
为了比较labmdas,我通常让接口扩展Serializable
,然后比较序列化的字节。不是很好,但在大多数情况下都有效。
这个问题可以根据规范或实现来解释。显然,实现可能会发生变化,但当这种情况发生时,您可能愿意重写代码,所以我将同时回答这两个问题。
这也取决于你想做什么。您是在寻求优化,还是在寻求两个实例是(或不是)相同功能的铁一般保证?(如果是后者,你会发现自己与计算物理不一致,因为即使是像询问两个函数是否计算同一事物这样简单的问题也是不可判定的。)
从规范的角度来看,语言规范只promise计算(而不是调用)lambda表达式的结果是实现目标函数接口的类的实例。它并没有promise结果的身份或混叠程度。这是出于设计,为实现提供最大的灵活性以提供更好的性能(这就是lambdas比内部类更快的原因;我们不受内部类的“必须创建唯一实例”约束的约束)
所以基本上,规范不会给你太多,除了两个引用相等的lambda(==)将计算相同的函数。
从实现的角度来看,您可以得出更多结论。在实现lambdas的合成类和程序中的捕获站点之间存在(目前可能会改变)1:1的关系。所以两段独立的代码捕获“x-
如果您的lambda是可序列化的,那么它们将更容易放弃其状态,以换取牺牲一些性能和安全性(没有免费的午餐)
调整相等的定义可能是实用的一个领域是方法引用,因为这将使它们能够被用作侦听器并被正确地取消注册。这一点正在考虑之中。
我认为您要了解的是:如果两个lambda被转换为相同的函数接口,由相同的行为函数表示,并且具有相同的捕获参数,那么它们是相同的
不幸的是,这既很难做到(对于不可序列化的lambda,您无法获得它的所有组件),也不够(因为两个单独编译的文件可能会将相同的lambda转换为相同的函数接口类型,您无法判断)
EG讨论了是否要公开足够的信息来做出这些判断,以及lambdas是否应该实现更具选择性的equals
/hashCode
或更具描述性的toString。我们的结论是,我们不愿意支付任何性能成本来向调用方提供这些信息(糟糕的折衷,99.99%的用户因受益0.01%而受到惩罚)。
关于toString
的最终结论尚未达成,但仍有待将来再次讨论。但是,双方在这个问题上都有一些很好的论据,;这不是扣篮。
问题内容: 假设我有一个使用lambda表达式(闭包)定义的对象列表。有没有一种方法可以检查它们以便进行比较? 我最感兴趣的代码是 完整的代码是 似乎唯一的解决方案是将每个lambda定义为一个字段,并且仅使用这些字段。如果要打印出称为的方法,最好使用。lambda表达式有更好的方法吗? 此外,是否可以打印lambda并获得人类可读的内容?如果你打印而不是 得到类似的东西 甚至使用和方法。 问题答
我有一个比较器,它检查字符串是否为空,并返回-1。如果它们不是null,则进行比较。我想用lambda函数实现这个。 以下是代码: 我知道如何使用lambdas返回一个简单的比较器。我对如何实现上述代码感到困惑。
在java中,不能使用。compareTo()将基元类型(如int)与其他类型进行比较。 如果两个整数小于零,有没有办法比较?我试图将整数与数组中的点进行比较。 谢啦! 解决方法:抱歉,大家都有一秒钟的大脑抽筋。我忘记了a.compareTo(b)根据第一个值是否小于(返回-1)、等于(返回0)或大于(返回1)返回-1、0或1。我的代码是int.compareTo(数组)
我正在做一个关于java类的介绍的作业,该作业要求使用方法将温度从摄氏转换为华氏,反之亦然。它需要使用三种比较方法,而我无法弄清楚该把什么放进去。以下是说明: 三种比较方法: -此方法将另一个温度作为参数,如果调用对象具有与other相同的温度,则返回true,否则返回false。注意,摄氏温度可以等于华氏温度,如上式所示。 -如果调用对象的温度低于其他温度,则此方法将返回true,否则返回fal
谁能解释一下为什么下面的代码不起作用: 但这一个有效: 换句话说,与创建普通类实例相比,接口实现何时是可互换的?当我使用compareTo()方法时会出现错误,该方法是Comparable接口的一部分,由所有包装类(如整数)实现。 所以我猜
我有一个关于compareTo函数如何帮助比较器排序的问题,即o1。比较(o2)与o2。比较(o1) 如果两个字符串相等,则此方法返回0,否则返回正值或负值。如果第一个字符串在词典上大于第二个字符串,则结果为正,否则结果为负。 上面的陈述很简单,但是为什么o1.compare(o2)会给我一个升序,而o2.compare(o1)给了我一个降序? 如果我有整数值“5,10,3”,我得到3,5,10和