Ich habe diese (scheinbar) unschuldig Code (in diesem JUnit-Testfall vereinfacht hier):Warum kann der Oracle Java Compiler die Grenzen hier nicht ableiten, aber Eclipse kann?
import static org.hamcrest.Matchers.instanceOf;
import static org.junit.Assert.assertThat;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.function.Supplier;
import org.junit.Test;
public class GenericsTest {
private static boolean doFail;
private static Map<String, Number> createMap() {
if (doFail) {
throw new IllegalArgumentException();
}
return new HashMap<>();
}
public static <T> T get(final Callable<T> _valueCreator, final Supplier<T> _errorValue) {
try {
return _valueCreator.call();
} catch (final Exception e) {
return _errorValue.get();
}
}
public static Map<String, Number> getCachedMap() {
return get(GenericsTest::createMap, Collections::emptyMap);
}
@Test
public void testSuccess() {
doFail = false;
assertThat(getCachedMap(), instanceOf(HashMap.class));
}
@Test
public void testFail() {
doFail = true;
assertThat(getCachedMap(), instanceOf(Collections.EMPTY_MAP.getClass()));
}
}
Das Problem in der Linie liegt return get(GenericsTest::createMap, Collections::emptyMap)
: das Eclipse-Compiler ein Problem hier nicht sehen (und ich bin so), kompiliert und führt den Test erfolgreich durch und ist erfolgreich.
Allerdings, wenn ich diese auf der Befehlszeile kompilieren (Maven 3, Oracle JDK8 in diesem Fall, aber auch mit javac arbeitet nicht direkt) wird ein Compiler-Fehler ausgelöst:
.../GenericsTest.java:[23,19] incompatible types: inferred type does not conform to upper bound(s)
inferred: java.util.Map<? extends java.lang.Object,? extends java.lang.Object>
upper bound(s): java.util.Map<java.lang.String,java.lang.Number>,java.lang.Object
Ich würde denke, dass es sowohl vom Rückgabetyp (Map<String, Number>
) als auch von der Signatur von createMap
(gleich) möglich sein sollte, den erforderlichen Typ abzuleiten - und tatsächlich scheint es, dass der Eclipse-Compiler dazu in der Lage zu sein scheint. Der JDK-Compiler führt jedoch nur Map<Object, Object>
und schlägt daher fehl.
Ist dies ein JDK-Bug oder ein Eclipse-Compiler-Bug oder etwas anderes?
Sie scheinen es behoben zu haben. Ich habe gerade ein paar Experimente gemacht. Es kompiliert mit 'javac 1.8.0_65', aber nicht mit' javac 1.8.0_25'. Ich bin zu faul, um die genaue Version zu finden, wo dies behoben wurde. –
Es kompiliert nicht auf Ideone. https://ideone.com/UDHTXm –
@PaulBoddington danke, ich werde das versuchen. Wir haben 1.8.0_51, also scheint es eine kürzlich behobene Lösung zu sein. –