2015-12-01 10 views
5

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?

+2

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

+0

Non si compila su Ideone. https://ideone.com/UDHTXm –

+0

@PaulBoddington grazie, ci proverò. Abbiamo 1.8.0_51 quindi sembra essere una correzione recente. –

risposta

1

Si trattava effettivamente di un bug, lo stesso codice si compila bene con JDK 1.8.0u66 ma non con 1.8.0u51 che avevo prima.

3

Questo sembra un bug. Mi prenderò cura di esso e probabilmente aggiungerò una risposta migliore una volta che avremo maggiori informazioni sul perché questo sta accadendo. Ho archiviato questa voce di bug JDK-8043926 per tracciarlo.

Problemi correlati