从java8迁移到java9时,对方法的引用是不明确的

Ism*_*yen 11 java compiler-errors java-8 functional-interface java-9

我正在将项目从JAVA 8迁移到JAVA 9,我在使代码工作时遇到了一些麻烦.所有工作在JAVA 8但在9我有以下错误:

Error java: reference to ok is ambiguous
      both method <T>ok(java.util.function.Supplier<T>)  and method ok(web.Procedure) match
Run Code Online (Sandbox Code Playgroud)

这是我调用方法时的代码:

public ResponseEntity<List<MailTemplateDto>> mailTemplateFindAll() {
    return ok(() -> mailTemplateService.findAll());
}
Run Code Online (Sandbox Code Playgroud)

这是实施:

 public <T> ResponseEntity<T> ok(Supplier<T> action) {
     return this.body(HttpStatus.OK, action);
 }

 public <T> ResponseEntity<T> ok(T body) {
     return this.ok(() -> {
         return body;
     });
 }

 public ResponseEntity<Void> ok(Procedure action) {
     action.invoke();
     return this.status(HttpStatus.OK);
 }

 public ResponseEntity<Void> ok() {
     return this.status(HttpStatus.OK);
 }
Run Code Online (Sandbox Code Playgroud)

Procedure接口的代码:

@FunctionalInterface
public interface Procedure {
    void invoke();
}
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?


可重现的代码 ::

public class Q48227496 {

    public A<?> test() {
        return ok(() -> System.out.append("aaa"));
    }

    private class A<T> {
    }

    private <T> A<T> ok(java.util.function.Supplier<T> action) {
        return new A<>();
    }

    public <T> A<T> ok(T body) {
        return new A<>();
    }

    private <T> A<T> ok(Procedure action) {
        return new A<>();
    }

    public <T> A<T> ok() {
        return new A<>();
    }

    @FunctionalInterface
    public interface Procedure {
        void invoke();
    }
}
Run Code Online (Sandbox Code Playgroud)

导致编译器出现以下错误::

error: reference to ok is ambiguous
        return ok(() -> System.out.append("aaa"));
               ^
  both method <T#1>ok(Supplier<T#1>) in Q48227496 and method <T#2>ok(Procedure) in Q48227496 match
  where T#1,T#2 are type-variables:
    T#1 extends Object declared in method <T#1>ok(Supplier<T#1>)
    T#2 extends Object declared in method <T#2>ok(Procedure)
Run Code Online (Sandbox Code Playgroud)

Hol*_*ger 8

这是一个错误.

据报道它有错误ID:JDK-8195598


我进一步简化了你的例子:

public class Q48227496 {
    public CompletableFuture<?> test() {
        return ok(() -> System.out.append("aaa"));
    }
    public <T> CompletableFuture<T> ok(Supplier<T> action) {
        return CompletableFuture.supplyAsync(action);
    }
    public <T> CompletableFuture<T> ok(T body) {
        return CompletableFuture.completedFuture(body);
    }
    public CompletableFuture<Void> ok(Runnable action) {
        return CompletableFuture.runAsync(action);
    }
}
Run Code Online (Sandbox Code Playgroud)

这在使用" reference to ok is ambiguous" 的Java 9的发行版本中失败,表示" both method <T>ok(Supplier<T>) in Q48227496 and method ok(Runnable) in Q48227496 match".

但只是改变方法的顺序

public class Q48227496 {
    public CompletableFuture<?> test() {
        return ok(() -> System.out.append("aaa"));
    }
    public <T> CompletableFuture<T> ok(T body) {
        return CompletableFuture.completedFuture(body);
    }
    public <T> CompletableFuture<T> ok(Supplier<T> action) {
        return CompletableFuture.supplyAsync(action);
    }
    public CompletableFuture<Void> ok(Runnable action) {
        return CompletableFuture.runAsync(action);
    }
}
Run Code Online (Sandbox Code Playgroud)

使编译器接受代码而没有任何错误.

因此,显然,这是一个编译器错误,因为方法声明的顺序不应该对代码的有效性产生影响.

此外,删除该ok(T)方法使代码被接受.

请注意,只要编译器接受代码,它就会认为ok(Supplier)更具体ok(Runnable),这是与两者匹配的函数参数的预期行为.

  • @IsmailAlehyen如[这里](/sf/ask/3375924751/#comment83503368_48227496),你可以控制目标方法只是括号,即`public A <?> test(){return ok(() - >(getString())); `)已经足以明确地调用期望`Supplier`的方法(因为`(表达式)`不是语句,而`public A <?> test(){return ok(() - > {getString() );}})`将始终调用期望`Procedure`的方法,作为`{statement; }`(没有`return`)不是表达式. (5认同)
  • 刚修好最新的jdk/jdk:http://hg.openjdk.java.net/jdk/jdk/rev/db044d7e9885感谢您的报告. (2认同)