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

reference to method is ambiguous when migrating from java8 to java9

我正在将一个项目从 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

调用方法时的代码如下:

public ResponseEntity<List<MailTemplateDto>> mailTemplateFindAll() {
    return ok(() -> mailTemplateService.findAll());
}

这是实现:

 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);
 }

过程接口代码:

@FunctionalInterface
public interface Procedure {
    void invoke();
}

有什么想法吗?


可重现代码 ::

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();
    }
}

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

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)

这是一个错误。

已报告错误 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);
    }
}

这在 Java 9 的发布版本中失败,带有“reference to ok is ambiguous”,声明“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);
    }
}

使编译器无任何错误地接受代码。

所以,很明显,这是一个编译器错误,因为方法声明的顺序永远不会影响代码的有效性。

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

请注意,无论何时编译器接受代码,它都会认为 ok(Supplier)ok(Runnable) 更具体,这是匹配两者的函数参数的预期行为。