gpt4 book ai didi

java - 有没有办法比较 lambdas?

转载 作者:IT老高 更新时间:2023-10-28 11:50:58 26 4
gpt4 key购买 nike

假设我有一个使用 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()

甚至使用 this.toString 和方法。

my-ClosureEqualsMain.a();

最佳答案

这个问题可以相对于规范或实现来解释。显然,实现可能会发生变化,但你可能愿意在发生这种情况时重写你的代码,所以我会同时回答。

这也取决于你想做什么。您是在寻找优化,还是在寻找两个实例是(或不是)相同功能的铁定保证? (如果是后者,您会发现自己与计算物理学不一致,因为即使是询问两个函数是否计算相同事​​物这样简单的问题也是无法确定的。)

从规范的角度来看,语言规范只 promise 评估(而不是调用)lambda 表达式的结果是实现目标函数接口(interface)的类的实例。它不 promise 结果的身份或混叠程度。这是设计使然,为实现提供最大的灵 active 以提供更好的性能(这就是 lambda 比内部类更快的原因;我们不受内部类的“必须创建唯一实例”约束。)

所以基本上,规范并没有给你太多,除非显然两个引用相等 (==) 的 lambda 将计算相同的函数。

从实现的角度来看,您可以得出更多的结论。实现 lambdas 的合成类与程序中的捕获站点之间存在(目前可能会改变)1:1 的关系。因此,捕获“x -> x + 1”的两个单独的代码位可以很好地映射到不同的类。但是,如果您在同一个捕获站点评估同一个 lambda,并且该 lambda 是非捕获的,那么您会得到相同的实例,可以将其与引用相等性进行比较。

如果您的 lambda 是可序列化的,它们将更容易放弃其状态,以换取一些性能和安全性的牺牲(没有免费的午餐。)

调整相等定义的一个实际领域是方法引用,因为这将使它们能够用作监听器并被正确地取消注册。正在考虑中。

我认为你想要得到的是:如果两个 lambda 被转换为相同的功能接口(interface),由相同的行为函数表示,并且具有相同的捕获参数,它们是相同的

不幸的是,这既很难做到(对于不可序列化的 lambda,您根本无法获得其中的所有组件)而且还不够(因为两个单独编译的文件可以将相同的 lambda 转换为相同的功能接口(interface)类型,而你无法分辨。)

EG 讨论了是否公开足够的信息以便能够做出这些判断,以及讨论 lambdas 是否应该实现更具选择性的 equals/hashCode 或更具描述性的 toString .结论是,我们不愿意为向调用者提供这些信息而付出任何性能成本(糟糕的权衡,惩罚 99.99% 的用户以获取 0.01% 的好处)。

关于 toString 的最终结论尚未达成,但仍待将来重新审视。但是,在这个问题上,双方都提出了一些很好的论据;这不是灌篮。

关于java - 有没有办法比较 lambdas?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24095875/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com