2015-04-30 3 views
11

Ho aggiornato da Java 8u5 a 8u45 e alcuni codici precedentemente funzionanti non compaiono più. Il problema è che, per metà del tempo in cui ciò accade, è stato un cambiamento intenzionale, quindi non riesco a capire se si tratta di un bug o meno.Questo errore generico esoterico è un bug del compilatore o una nuova restrizione? (il tipo dedotto non è conforme ai limiti superiori)

(ho anche testato fino a U25 e tutte le versioni fa la stessa cosa come U45.)

Ma in sostanza, si ha a che fare con più punti di ritorno da un metodo. es .:

import java.sql.Connection; 
import java.util.Collections; 
import java.util.HashSet; 
import java.util.Set; 

public class CompilerIssue 
{ 
    public Set<String> test(int value) 
    { 
     return perform(connection -> { 
      if (value % 2 == 0) 
      { 
       return Collections.<String>emptySet(); 
      } 
      else 
      { 
       return new HashSet<>(10); 
      } 
     }); 
    } 

    <V> V perform(BusinessLogic<V> logic) 
    { 
     // would usually get a connection 
     return null; 
    } 

    interface BusinessLogic<V> 
    { 
     V execute(Connection connection) throws Exception; 
    } 
} 

javac dà:

Error:(12, 23) java: incompatible types: inferred type does not conform to upper bound(s) 
    inferred: java.util.Set<? extends java.lang.Object> 
    upper bound(s): java.util.Set<java.lang.String>,java.lang.Object 

IDEA, come di consueto, con questo genere di cose, non può vedere tutto il problema.

Conosco già la correzione - sostituire HashSet<> con HashSet<String>. Ma abbiamo usato questo tipo di struttura in modo pervasivo attraverso il nostro codice, quindi prima di passare il tempo a cambiarlo tutto, mi piacerebbe sapere: questo è un bug, o il vecchio comportamento era il bug?

(Se si tratta di un bug, poi devo segnalare un bug per Oracle. Se si tratta di una caratteristica, allora devo segnalare un bug per idea in proposito pensare che è OK.)

+0

Prevedo anche che 'Collections.emptySet()' funzioni, ma ha lo stesso errore. – xehpuk

+0

@xehpuk sì, se Collections.emptySet() e nuovo HashSet vengono utilizzati, si ottiene anche l'errore. Sembra che il nuovo comportamento (bug o altro) sia che ogni punto di ritorno è guardato ma tutti devono essere espliciti, mentre il vecchio comportamento sembrava più l'opposto, che bastava renderne uno esplicito e implicherebbe il resto – Trejkaz

risposta

5

Per quanto mi può vedere che è un bug e proviene da Oracle, non sta inferendo correttamente il tipo dal tipo di destinazione (il tipo che la frase restituisce prevede invece di restituire), è in qualche modo confrontando il limite superiore di restituisce frasi : (return Collections.<String>emptySet(); e return new HashSet<>(10);).

Nella seconda dichiarazione di restituzione il limite superiore di appena new HashSet<>(10) sarebbe Object, ma il tipo potrebbe essere desunto dal tipo restituito che è effettivamente <String>. Prova solo come test commentando la prima dichiarazione di ritorno e tornare nulla, invece, e compilare:

public class CompilerIssue 
{ 
    public Set<String> test(int value) 
    { 
     return perform(connection -> { 
      if (value % 2 == 0) 
      { 
       return null; // COMMENTED OUT FOR TESTING PURPOSES Collections.<String>emptySet(); 
      } 
      else 
      { 
       return new HashSet<>(10); 
      } 
     }); 
    } 

    <V> V perform(BusinessLogic<V> logic) 
    { 
     // would usually get a connection 
     return null; 
    } 

    interface BusinessLogic<V> 
    { 
     V execute(Connection connection) throws Exception; 
    } 
} 

questo sarebbe compilare e che sarebbe corretto dedurre il tipo di valore corretto di HashSet<>(10) dovrebbe essere String.