Tengo esta clase llamada Container
:
public class Container {
private final Map<String, Object> map = new HashMap<>();
public void put(String name, Object value) {
map.put(name, value);
}
public Container with(String name, Object value) {
put(name, value);
return this;
}
public Object get(String name) {
return map.get(name);
}
public <R> R get(String name, Function<Object, R> mapper) {
Object value = get(name);
if (null == value) {
return null;
}
return mapper
.apply(value);
}
public <R> R get(String name, Class<R> type) {
Object value = get(name);
if (null == value) {
return null;
}
if (type.isAssignableFrom(value.getClass())) {
return type
.cast(value);
}
throw new ClassCastException(String
.format("%s -> %s", value.getClass(), type));
}
}
y la clase llama Token
:
public class Token {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public Token withValue(String value) {
setValue(value);
return this;
}
}
y, finalmente, una clase de prueba para la Token
clase
public class TokenTest {
@Test
public void verifyToken() {
verify("bar", new Token()
.withValue("bar"));
}
@Test
public void verifyContainer() {
Container tokens = new Container()
.with("foo", "bar")
.with("baz", "bat");
verify("bar", tokens.get("foo", String.class));
verify("bat", tokens.get("baz", String::valueOf)); // line 21
}
private void verify(String expected, String actual) {
verify(expected, new Token()
.withValue(actual));
}
private void verify(String expected, Token actual) {
Assert
.assertEquals(expected, actual.getValue());
}
}
Las compilaciones de prueba y se ejecuta solo archivo en eclipse.
Cuando la construcción de la línea commad
mvn clean test
se eleva un error de compilación:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:testCompile (default-testCompile) on project ambiguous: Compilation failure
[ERROR] /C:/data/projects/java/ambiguous/src/test/java/ambiguous/TokenTest.java:[21,9] reference to verify is ambiguous
[ERROR] both method verify(java.lang.String,java.lang.String) in ambiguous.TokenTest and method verify(java.lang.String,ambiguous.Token) in ambiguous.TokenTest match
La compilación también falla cuando cambio de línea 21
a uno de
verify("bat", tokens.get("baz", e -> String.valueOf(e)));
verify("bat", tokens.get("baz", e -> e.toString));
Cuando cambio la línea a una de
verify("bat", tokens.get("baz", String.class));
verify("bat", tokens.get("baz", Object::toString));
compilación es exitosa.
No puedo undestand qué se eleva este error compiliation.
Me encontré con los enlaces follwong boxeo y unboxing , múltiples tipos genéricos y tipos de intersección y el eclipse de error del compilador , pero todavía no puedo relacionar con las causas mencionadas.
Mi pregunta es, ¿qué hace que el compilador piensa que ambas firmas del verify
método son coincidentes cuando el asignador String::valueOf
se pasa al get
método?
Para la compilación la siguiente JDK se utiliza (con Maven y Gradle):
$ java -version
openjdk version "1.8.0_201-1-ojdkbuild"
OpenJDK Runtime Environment (build 1.8.0_201-1-ojdkbuild-b09)
OpenJDK 64-Bit Server VM (build 25.201-b09, mixed mode)
De acuerdo con los JLS §15.12.2.2 :
Una expresión argumento se considera pertinente para la aplicabilidad de un método potencialmente aplicable
m
a menos que tenga una de las siguientes formas:
- Una expresión lambda implícitamente escrito 1 .
- Una expresión de referencia método inexacta 2 .
- [...]
Por lo tanto:
verify("bar", tokens.get("foo", e -> String.valueOf(e)));
una expresión lambda implícitamente escrito e -> String.valueOf(e)
se salta desde el registro de aplicación durante la resolución de sobrecarga - ambos verify(...)
métodos sean aplicables, - de ahí la ambigüedad.
En comparación, he aquí algunos ejemplos que van a trabajar, debido a que los tipos se especifican explícitamente:
verify("bar", tokens.get("foo", (Function<Object, String>) e -> String.valueOf(e)));
verify("bar", tokens.get("foo", (Function<Object, String>) String::valueOf));
1 - Una expresión lambda implícitamente escrito es una expresión lambda, donde se infieren los tipos de todos sus parámetros formales.
2 - Una referencia método inexacta - uno con múltiples sobrecargas.