【发布时间】:2018-01-12 13:42:41
【问题描述】:
我正在将一个项目从 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);
}
Procedure接口代码:
@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();
}
}
导致java9 编译器出现以下错误::
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)
【问题讨论】:
-
这里是错误 github.com/alehyen/demo 的重现,但如果您将 Controller.java 中的代码更改为 @RequestMapping(method = RequestMethod.GET) public ResponseEntity
userGet() { return ok( () -> "你好世界"); } 它会起作用的 -
Java 9 中的问题是因为有 3 个 one-arg
ok方法可供选择(问题的前三个)。如果你注释掉其中一个,编译器会很乐意在另外两个中选择一个,大概是基于 JLS 规则。它从不选择收到T body的那个,当那个被评论时,它会选择收到Supplier<T>的那个。至于为什么这在 Java 8 中有效,但在 Java 9 中无效,我不知道......根据 JLS,我什至不敢猜测哪个是正确的行为...... -
@FedericoPeraltaSchaffner 当然,这与特殊的 void 兼容性规则以及表达式可以用作语句 (docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.8) 的事实有关,但是男孩这很复杂(并且具有误导性!)
-
@Eugene 我认为这是一个编译器错误 w.r.t.针对重载方法的优先级规则。而且我确信这是一个错误,因为它适用于两种方法,但不适用于三种方法,无论这两种方法组合是什么。如果不是错误,我们应该能够找到产生歧义的方法对。
-
@Eugene 请注意,将 ExpessionStatement 转换为 Statement 不需要 return 语句;花括号就足够了。你可以把它记住为括号消歧:
args -> { exprStmt; }使它成为一个语句,args -> ( exprStmt )使它成为一个表达式。否则,接受非void函数的方法应该获胜。有趣的是,Java 9 的编译器完全同意它,it just doesn’t like the method order...
标签: java9 java compiler-errors java-8 java-9 functional-interface