番石榴期货的暧昧lambda超载 [英] Ambiguous lambda overload in Guava Futures

查看:158
本文介绍了番石榴期货的暧昧lambda超载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我相信我在这里遇到了一个日食错误,但我想确认一下。

我使用的是java 8(jdk 1.8.0_102),我的代码正常编译,但是eclipse给了我错误。

I believe I am facing an eclipse bug here, but I'd like to confirm.
I am using java 8 (jdk 1.8.0_102), and my code compiles normally, but eclipse gives me an error.

我的代码如下所示:

public ListenableFuture<ProtoBufExchange> myMethod(
   //some code here
   return Futures.transform(future,(Request.Builder reqBuilder) -> {

    //some code here

    return Futures.immediateFuture(exchange);
  }

eclipse中显示的错误是这样:

The error shown in eclipse is this:


方法转换(ListenableFuture< Request.Builder>,AsyncFunction<?super Request.Builder,?extends
ProtoBufExchange>)对于Futures类型是不明确的。

The method transform(ListenableFuture<Request.Builder>, AsyncFunction<? super Request.Builder,? extends ProtoBufExchange>) is ambiguous for the type Futures.

如果我投了一个演员,eclipse不会抱怨:

If I put a cast, eclipse will not complain:

public ListenableFuture<ProtoBufExchange> myMethod(
   //some code here
   return Futures.transform(future,(AsyncFunction<Request.Builder, ProtoBufExchange>) (Request.Builder reqBuilder) -> {

    //some code here

    return Futures.immediateFuture(exchange);
  }

我知道番石榴15.0 Future.transform()是overloa ded,下面有两个表单(在较新的番石榴版本上,async方法有不同的名称):

I know the guava 15.0 Future.transform() is overloaded, with the two forms below (on newer guava versions the async method has a different name):

transform(ListenableFuture<I> input, Function<? super I,? extends O> function)

transform(ListenableFuture<I> input, AsyncFunction<? super I,? extends O> function)

但不知何故,jdk编译器可以解决这个问题。也许是因为在上面的代码中,如果我们实现的是Function而不是AsyncFunction,Futures.transform的返回类型将与方法返回类型不匹配。

But somehow the jdk compiler resolves this ambiguation. Maybe because in the code above, if we were implementing a Function, rather than an AsyncFunction, the return type of Futures.transform would not match with the method return type.

这是日食的错误吗?我在这里错过了什么吗?

Is it a bug on eclipse? Am I missing something here?

关于我的环境的更多细节:

More details on my environment:

jdk:1.8.0_102

eclipse: 4.6.2

guava:15.0

jdk: 1.8.0_102
eclipse: 4.6.2
guava: 15.0

推荐答案

明确键入的lambda表达式和隐式键入的lambda表达式。

There is a distinction between "explicitly typed lambda expressions" and "implicitly typed lambda expressions".

形式的隐式类型lambda表达式 - > expressiorOrBlock (name [,name] *) - > expressionOrBlock 需要其上下文(即已解析的方法)来确定其类型,因此不用于消除重载方法的歧义。这样做并不是不可能的,但是由于产生的复杂性,规范明确排除了它。

An implicitly typed lambda expression of the form name -> expressiorOrBlock or (name[,name]*) -> expressionOrBlock requires its context, i.e. a resolved method, to determine its type, hence isn’t used to disambiguate overloaded methods. It wouldn’t be impossible to do this, but due to the resulting complexity, it was explicitly ruled out by the specification.

<$>形式的显式类型的lambda表达式c $ c>(类型名称[,类型名称] *) - > expressionOrBlock 拥有确定其功能签名所需的一切,包括它们的返回类型,允许使用它们消除重载方法的歧义。

Explicitly typed lambda expressions of the form (Type name[, Type name]*) -> expressionOrBlock have everything needed to determine their functional signature, including their return type, which allows to use them to disambiguate overloaded methods.

提供简单示例:

interface F<T,R> {
    R apply(T t);
}
interface AF<T,R> {
    Future<R> apply(T t);
}
static <T,R> Future<R> method(F<T,R> f) {
    return null;
}
static <T,R> Future<R> method(AF<T,R> f) {
    return null;
}
public static void main(String[] args) {
    // these two don't compile
    method(x -> "bla");
    method(x -> new FutureTask<String>(null));

    // these two do compile
    method((Object x) -> "bla");
    method((Object x) -> new FutureTask<String>(null));
}

正式规则在 JLS,§15.12.2.5。选择最具体的方法,但它也包含一个非正式的提示:

The formal rules are specified in JLS, §15.12.2.5. Choosing the Most Specific Method, but it also contains an informal hint:


非正式的直觉是一种方法更具体如果第一个方法处理的任何调用都可以传递给另一个没有编译时错误的调用,那么比另一个。

The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time error.

我认为,很容易看出每个可以通过方法(AF)处理的电话也可以通过方法(F)来处理,而相反的情况不适用,即方法((对象x) - >bla)调用只能由方法(F),所以它不含糊,而方法((对象x) - >新的FutureTask< String>(null))可由两者处理,但方法(AF) 更具体

I think, it’s easy to see that every call that can be handled by method(AF) could also be handled by method(F), while the opposite doesn’t apply, i.e. the method((Object x) -> "bla") invocation can only be handled by method(F), so it’s not ambiguous, whereas method((Object x) -> new FutureTask<String>(null)) could be handled by both, but method(AF) is more specific.

相关正式部分是:

功能接口类型 S 比功能接口类型 T 更具体表达式 e 如果 T 不是 S的子类型并且以下之一为真(其中 U 1 ... U k R 1 S 捕获的函数类型的参数类型和返回类型,以及 V 1 ... V k R 2 是函数类型的参数类型和返回类型 T ):

A functional interface type S is more specific than a functional interface type T for an expression e if T is not a subtype of S and one of the following is true (where U₁ ... Uk and R₁ are the parameter types and return type of the function type of the capture of S, and V₁ ... Vk and R₂ are the parameter types and return type of the function type of T):


  • 如果e是一个显式类型的lambda表达式(§15.27.1),然后满足下列条件之一:


    • R 2 void

    • R 1 <: R 2

    • ...

    • If e is an explicitly typed lambda expression (§15.27.1), then one of the following is true:
      • R₂ is void.
      • R₁ <: R₂.

      所以在这个涉及明确键入的lambda expre的特定情况下ssion,函数类型的返回类型已足以消除歧义。

      So in this specific case involving an explicitly typed lambda expression, the return type of the functional type is already sufficient to disambiguate.

      但请注意,编译示例代码也会产生警告:

      But note that compiling the example code also produces the warning:


      警告:[重载] < T#1,R#1>方法(F ...可能与< T#2,R#2>方法(AF< T#2,R#2>)

      提醒隐式类型的lambda表达式对于这样的重载方法总是不明确的,并且使用显式类型lambda表达式的方法选择可能不直观。

      Reminding that implicitly typed lambda expressions will always be ambiguous with such overloaded methods and also the method selection with explicitly type lambda expressions might not be intuitive.

      这篇关于番石榴期货的暧昧lambda超载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆