2015-12-01 1 views
5

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?

+2

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. –

+0

Es kompiliert nicht auf Ideone. https://ideone.com/UDHTXm –

+0

@PaulBoddington danke, ich werde das versuchen. Wir haben 1.8.0_51, also scheint es eine kürzlich behobene Lösung zu sein. –

Antwort

1

Es war in der Tat ein Fehler, der gleiche Code kompiliert in Ordnung mit JDK 1.8.0u66, aber nicht mit 1.8.0u51, die ich vorher hatte.

3

Das sieht wie ein Fehler aus. Ich werde mich darum kümmern und wahrscheinlich eine bessere Antwort hinzufügen, sobald wir mehr Informationen darüber haben, warum dies geschieht. Ich habe diesen Fehlereintrag JDK-8043926 abgelegt, um es zu verfolgen.