2015-10-14 16 views
5

Domanda da un libro:Java 8 - di default metodi - rischi di codice legacy

In passato (pre-Java 8), è stato detto che si tratta di cattiva forma per aggiungere i metodi per un'interfaccia perché spezzerebbe il codice esistente. Ora ti viene detto che va bene aggiungere nuovi metodi, purché tu fornisca anche un'implementazione predefinita.

  1. Quanto è sicuro? Descrivere uno scenario in cui il nuovo metodo stream dell'interfaccia Collection causa la compilazione del codice legacy.
  2. E la compatibilità binaria? Sarà codice legacy da un file JAR correre ancora?"

Le mie risposte sono le seguenti, ma io non sono del tutto sicuro su di loro.

  1. è sicuro solo se il codice legacy non fornisce un metodo con lo stesso nome stream e con la stessa firma (ad esempio in una classe precedente che implementa Collection) Altrimenti, questo vecchio codice legacy non riuscirà a compilare.
  2. Penso che la compatibilità binaria sia preservata, il codice precedente dal vecchio file JAR verrà comunque eseguito Ma non ho argomenti chiari su questo S.

Qualcuno potrebbe confermare o rifiutare queste risposte o semplicemente aggiungere ulteriori argomenti, riferimenti o chiarezza a queste risposte?

+0

[Correlato] (http://stackoverflow.com/a/22618640/335858). – dasblinkenlight

+1

Fare ciò preservando la compatibilità binaria è stata la motivazione principale dell'aggiunta di metodi predefiniti alla lingua.L'aggiunta di un valore predefinito a un metodo esistente è binario e compatibile all'origine; l'aggiunta di un nuovo metodo con un valore predefinito è binario e compatibile con la sorgente (interazioni modulo con metodi di contrasto in sottoclassi - ha caratteristiche di compatibilità identiche all'aggiunta di un nuovo metodo a una classe non finale.) –

+1

Mentre la compatibilità binaria viene mantenuta, è possibile che ci sia ancora i problemi sorgono quando interagisce con il comportamento della libreria JRE, come in [questo scenario] (http://stackoverflow.com/q/26816650/2711488). Si può anche considerare che un metodo potrebbe avere una firma * compatibile *, quindi, inizia a sovrascrivere un nuovo metodo 'default' senza intenderlo ... – Holger

risposta

8
  1. Il nuovo metodo stream() predefinito in Collection restituisce una Stream<E>, anche un nuovo tipo in Java 8. Codice Legacy fallirà compilazione se contiene un metodo stream() con la stessa firma, ma tornando un'altra cosa, con un conseguente scontro di tipi di ritorno.

  2. Il codice legacy continuerà a essere eseguito finché non viene ricompilato.

In primo luogo, in 1.7, impostare la seguente:

public interface MyCollection { 
    public void foo(); 
} 

public class Legacy implements MyCollection { 
    @Override 
    public void foo() { 
     System.out.println("foo"); 
    } 

    public void stream() { 
     System.out.println("Legacy"); 
    } 
} 

public class Main { 
    public static void main(String args[]) { 
     Legacy l = new Legacy(); 
     l.foo(); 
     l.stream(); 
    } 
} 

Con -source 1.7 -target 1.7, questo viene compilato ed eseguito:

$ javac -target 1.7 -source 1.7 Legacy.java MyCollection.java Main.java 
$ java Main 
foo 
Legacy 

Ora a 1.8, aggiungiamo il metodo flusso di MyCollection .

public interface MyCollection 
{ 
    public void foo(); 
    public default Stream<String> stream() { 
     return null; 
    } 
} 

compiliamo solo MyCollection in 1.8.

$ javac MyCollection.java 
$ java Main 
foo 
Legacy 

Naturalmente non possiamo ricompilare Legacy.java più.

$ javac Legacy.java 
Legacy.java:11: error: stream() in Legacy cannot implement stream() in MyCollection 
    public void stream() 
       ^
    return type void is not compatible with Stream<String> 
1 error 
+5

Si noti che questo caso angolo di compatibilità non è nuovo con i metodi predefiniti; lo stesso problema è stato presente con Java 1.0 se si aggiunge un metodo a una superclasse che è incompatibile con il metodo con lo stesso nome in alcune sottoclassi. L'aggiunta di metodi alle interfacce con valori predefiniti ha le stesse caratteristiche di compatibilità con l'aggiunta di metodi alle classi. –

+3

Penso che i metodi di contrasto siano il problema più piccolo man mano che il compilatore li individua. Un problema più grande si verifica quando la firma non si scontra. Con 'stream()', è impossibile in quanto il tipo di ritorno è una nuova classe. Ma pensa a 'sort (Comparator)'. Potresti avere un tale metodo nella tua implementazione 'List' personalizzata prima di Java 8, e prima di Java 8, implementarla delegando a' Collections.sort' sarebbe ragionevole. Ora, 'Collections.sort' delega a' List.sort' che il metodo pre-Java 8 sovrascrive senza intenzione. Il compilatore non ti dirà di questo problema ... – Holger