【发布时间】:2016-07-20 02:38:53
【问题描述】:
这是我在Java中引入lambda之后一直想知道的一个问题,并受到a related question的启发,我想我可能会在这里提出来,看看是否有任何想法。
(旁注:有一个similar question for C#,但我没有找到适用于 Java 的。Java 中关于“将 lambda 存储在变量中”的问题总是提到 type 变量是固定的 - 这正是我试图规避的)
Lambda 表达式通过目标类型推断接收它们需要的类型。这一切都由编译器处理。比如函数
static void useF(Function<Integer, Boolean> f) { ... }
static void useP(Predicate<Integer> p) { ... }
都可以用相同的 lambda 表达式调用:
useF(x -> true);
useP(x -> true);
表达式将一次表现为实现Function<Integer,Boolean>接口的类,一次表现为实现Predicate<Integer>接口的类。
但不幸的是,没有办法将 lambda 表达式存储为适用于这两个函数的类型,例如 in
GenericLambdaTypelambda = x -> true;
这种“通用 lambda 类型”必须编码 可以由给定 lambda 表达式实现的方法的类型。所以在这种情况下,它会是
(Ljava.lang.Integer)Ljava.lang.Booleanlambda = x -> true;
(基于standard type signatures,用于说明)。 (这并非完全不合理:C++ lambda expressions 基本上就是这样做的……)
那么有没有任何方法来防止 lambda 表达式被解析为一种特定类型?
特别是,是否有任何技巧或解决方法允许使用相同的对象调用上面概述的 useF 和 useP 方法,如
useF(theObject);
useP(theObject);
这不太可能,所以我假设答案很明显是:“否”,但是:是否有 any 方法来编写 generic,魔术适应方法,例如
useF(convertToRequiredTargetType(theObject));
useP(convertToRequiredTargetType(theObject));
?
请注意,这个问题更多是出于好奇。所以我真的在寻找 any 方法来实现这一点(自定义预编译器或字节码操作除外)。
似乎没有简单的解决方法。通过将表达式包装到通用辅助方法中来推迟类型推断的天真尝试,如
static <T> T provide()
{
return x -> true;
}
当然失败了,声明“这个表达式的目标类型必须是一个函数式接口”(这里根本无法推断类型)。但我也考虑了其他选项,例如MethodHandles、残酷的未经检查的演员表或讨厌的反射黑客。一切似乎在编译后立即丢失,其中 lambda 隐藏在匿名类的匿名对象中,其唯一方法通过 InvokeVirtual 调用...
【问题讨论】:
-
一个
CallSite?基本上,这就是 lambda -
您是否正在寻找一种将适用的功能接口转换为等效的所需功能接口的方法,例如
Function<Integer, Boolean>到Predicate<Integer>?这样你就可以将一个 lambda 存储为一种功能接口类型的变量,但你可以将它用作另一种功能接口类型? -
@fge 我不确定 - 从查看文档来看,我不知道如何在这里应用它。 @rgettman 基本上是的。我知道可以将它包装到另一个 lambda 中,例如
useP(x -> f.apply(x));,但这通常不起作用。 -
@JornVernee 引用问题:“所以我真的在寻找任何方法来实现这一点(自定义预编译器或字节码操作除外)。”
-
@Marco13 抱歉,看了大约一个小时后,我陷入了沉思:/
标签: java generics lambda casting