我有這個(貌似)無辜的代碼(簡化成這個JUnit測試案例在這裏):爲什麼Oracle Java編譯器不能在此推斷邊界,但Eclipse可以?
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()));
}
}
問題在於行return get(GenericsTest::createMap, Collections::emptyMap)
:Eclipse編譯器不會在這裏看到一個問題(我也是),愉快地編譯和運行測試並且成功。
然而,當我編譯在命令行上(Maven的3,甲骨文JDK8在這種情況下,也不會用javac直接合作),編譯錯誤被拋出:
.../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
我會認爲從返回類型(Map<String, Number>
)以及從createMap
(相同)的簽名中,應該可以推斷出所需的類型 - 事實上,似乎Eclipse編譯器似乎能夠做到這一點。但是,JDK編譯器只會推斷Map<Object, Object>
並因此失敗。
這是一個JDK錯誤或Eclipse編譯器錯誤或其他東西?
他們似乎已經修復它。我剛剛做了一些實驗。它使用'javac 1.8.0_65'編譯,但不使用'javac 1.8.0_25'。我懶得找到確切的釋放,這是固定的。 –
它不在Ideone上編譯。 https://ideone.com/UDHTXm –
@PaulBoddington謝謝,我會嘗試。我們有1.8.0_51,所以它似乎是最近的修復。 –