Ho questo (apparentemente) codice di innocenti (semplificato in questo caso di test JUnit qui):Perché il compilatore Oracle Java non può inferire i limiti qui ma Eclipse può?
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()));
}
}
Il problema sta nella linea return get(GenericsTest::createMap, Collections::emptyMap)
: il compilatore Eclipse non vede un problema qui (e lo sono io), compila felicemente e esegue il test e ci riesce.
Tuttavia, quando compilo questo sulla riga di comando (Maven 3, Oracle JDK8 in questo caso, ma anche non funziona con javac direttamente), si butta un errore di compilazione:
.../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
vorrei pensate che sia dal tipo di ritorno (Map<String, Number>
) che dalla firma di createMap
(lo stesso) dovrebbe essere possibile dedurre il tipo richiesto - e in effetti sembra che il compilatore di Eclipse sembri essere in grado di farlo. Tuttavia, il compilatore JDK deduce solo Map<Object, Object>
e quindi non riesce.
Si tratta di un bug JDK o di un bug del compilatore Eclipse o qualcos'altro?
Sembra che l'abbiano risolto. Ho appena fatto alcuni esperimenti. Si compila usando 'javac 1.8.0_65', ma non usando' javac 1.8.0_25'. Sono troppo pigro per trovare l'esatto rilascio in cui è stato corretto. –
Non si compila su Ideone. https://ideone.com/UDHTXm –
@PaulBoddington grazie, ci proverò. Abbiamo 1.8.0_51 quindi sembra essere una correzione recente. –