Rog*_*ays 5 java functional-programming
给定以下恒等函数:
<T> Consumer<T> f(Consumer<T> c) { return c; } // (1)
<T,R> Function<T,R> f(Function<T, R> c) { return c; } // (2)
Run Code Online (Sandbox Code Playgroud)
我在 JDK 11 和 JDK 17 中观察到以下行为:
void _void() {}
f(x -> {}); // okay, dispatches to (1)
f(x -> { return; }); // okay, dispatches to (1)
f(x -> { _void(); }); // okay, dispatches to (1)
f(x -> _void()); // should dispatch to (1)
| Error:
| reference to f is ambiguous
| both method f(java.util.function.Function<java.lang.Object,java.lang.Object>) in
and method f(java.util.function.Consumer<java.lang.Object>) in match
int _one() { return 1; }
f(x -> 1); // okay, dispatches to (2)
f(x -> { return 1; }); // okay, dispatches to (2)
f(x -> { return _one(); }); // okay, dispatches to (2)
f(x -> _one()); // should dispatch to (2)
| Error:
| reference to f is ambiguous
| both method <T,R>f(java.util.function.Function<T,R>) in
and method <T>f(java.util.function.Consumer<T>) in match
Run Code Online (Sandbox Code Playgroud)
为什么编译器不能使用表达式的返回类型来解析这些符号?大括号版本工作得很好,我原以为它们会是更困难的情况。我知道您可以显式转换 lambda 函数,但这违背了我想要实现的目的。
x -> _void()并预计与(结果被丢弃)x -> one()兼容。Consumer<T>one()
当 lambda 主体是块类型时,编译器还会检查“返回”兼容性。\nJLS对于块主体的 void/value 兼容性相当明确:
\n\n\n如果块中的每个 return 语句都具有return 形式,则块 lambda 主体是 void 兼容的;.\n如果块 lambda 主体无法正常完成 (\xc2\xa714.21),并且块中的每个 return 语句都具有return Expression 的形式,则它是值兼容的;。
\n
虽然这并没有说明为什么单表达式体失败,但它准确地说明了块体编译的原因:编译器查看形式来return判断这些体与Consumeror的兼容性Function(在本例中)。
对于方法调用表达式,这是允许的:
\nConsumer<Integer> c = x -> one(); //discarded result\nFunction<T, Integer> f = x -> one(); //returned result\nRun Code Online (Sandbox Code Playgroud)\n不允许编译器解决您观察到的冲突。您可以使用块体重写相同的 lambda 表达式来解决冲突,这只是因为根据规范对块体进行了不同的检查。
\n我想我想说的是,更自然的问题是“为什么在这种情况下块体会编译”,因为我们通常不期望返回类型(形式?)参与重载解析。但是 lambda 表达式与类型的一致性是另一回事,不是吗……我认为这是特殊的行为(块类型有助于目标类型推断)。
\n| 归档时间: |
|
| 查看次数: |
221 次 |
| 最近记录: |