Domanda

Qualcuno sa perché:

public void foo()
{
    System.out.println("Hello");
    return;
    System.out.println("World!");
}

Dovrebbe essere segnalato come un "unreachable" in Eclipse, ma

public void foo()
{
    System.out.println("Hello");
    if(true) return;
    System.out.println("World!");
}

Si innesca solo una "Morti codice" avviso?

L'unica spiegazione che posso pensare è che il compilatore Java solo bandiere il primo, e che alcuni extra analisi in Eclipse figure fuori il secondo.Tuttavia, se questo è il caso, perché non è possibile che il compilatore Java capire questo caso in fase di compilazione?

Non sarebbe il compilatore Java la figura in fase di compilazione che il se(vero) non ha alcun effetto, producendo così un bytecode è essenzialmente identico?A che punto è raggiungibile codice di analisi applicata?

Credo che un più generale modo di pensare di questa domanda è:"quando è raggiungibile codice di analisi applicata"?Nella trasformazione del secondo frammento di codice Java per la finale di bytecode, sono sicuro che a un certo punto il "if(true)" runtime equivalente viene rimosso, e le rappresentazioni dei due programmi identici.Non sarebbe il compilatore Java quindi applicare il suo raggiungibile analisi del codice di nuovo?

È stato utile?

Soluzione

Il primo fa non compilazione (hai un errore), il secondo compilazione (hai appena ricevuto un avvertimento). Questa è la differenza.

Per quanto riguarda il motivo per cui Eclipse rileva codice morto, beh, questo è solo la comodità di uno strumento di sviluppo integrato con un built-in del compilatore, che può essere più finetuned al contrario di JDK per rilevare questo tipo di codice.

Aggiorna : il JDK effettivamente elimina codice morto

.
public class Test {
    public void foo() {
        System.out.println("foo");
        if(true)return;
        System.out.println("foo");
    }
    public void bar() {
        System.out.println("bar");
        if(false)return;
        System.out.println("bar");
    }
}

javap -c dice:

public class Test extends java.lang.Object{
public Test();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."":()V
   4:   return

public void foo();
  Code:
   0:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   ldc             #3; //String foo
   5:   invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/StrV
   8:   return

public void bar();
  Code:
   0:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   ldc             #5; //String bar
   5:   invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   8:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   11:  ldc             #5; //String bar
   13:  invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   16:  return

}

Per quanto riguarda il motivo per cui (Sun) non dà un avvertimento di questo, non ho idea :) Almeno il compilatore JDK ha in realtà DCE (guasto Codice Eliminazione) incorporato.

Altri suggerimenti

Codice irraggiungibile è un errore secondo il Linguaggio Java Spec.

Per citare il JLS:

L'idea è che ci deve essere un percorso di esecuzione dall'inizio del costruttore, di un metodo di istanza di inizializzazione o inizializzatore statico che contiene la dichiarazione la dichiarazione stessa.L'analisi prende in considerazione la struttura del bilancio.Fatta eccezione per il trattamento speciale di while, do, e per le dichiarazioni la cui espressione della condizione è il valore della costante è vero, i valori delle espressioni non sono presi in considerazione nell'analisi del flusso.

Che cosa significa, è che il if blocco non è preso in considerazione, dal momento che, se si passa attraverso uno dei percorsi del if istruzione, è possibile raggiungere la finale di istruzione di stampa.Se hai cambiato il tuo codice:

public void foo() {
    System.out.println("Hello");
    if (true)
        return;
    else
        return;
    System.out.println("World!");
}

poi, all'improvviso, non compilare più, dato che non vi è alcun percorso attraverso il if dichiarazione che non consentono l'ultima riga per essere raggiunto.

Che è, un Java compatibile compilatore non è consentito compilare il primo frammento di codice.Per ulteriori citare il JLS:

Come esempio, la seguente dichiarazione risultati in un errore di compilazione:

while (false) { x=3; }

perché l'istruzione x=3;non è raggiungibile;ma il superficialmente caso simile:

if (false) { x=3; }

non viene generato un errore di compilazione.Un compilatore ottimizzante può capire che l'istruzione x=3;non verrà mai eseguita, e può scegliere di omettere il codice per l'istruzione dal generati file di classe, ma l'istruzione x=3;non sono considerati come "irraggiungibile" in senso tecnico specificato qui.

Il secondo avvertimento che Eclipse fornisce, su codice morto, è un segnale generato dal compilatore, che non è "non raggiungibile", secondo i JLS, ma, in pratica, è.Questo è un ulteriore lint stile verificare che Eclipse fornisce.Questo è del tutto facoltativo, e, utilizzando l'Eclissi di configurazione, può essere disabilitato, o trasformato in un errore del compilatore, invece di un messaggio di avviso.

Questo secondo blocco è un codice "odore", if (false) i blocchi sono di norma inserita nel codice di disattivazione per scopi di debug, avendo lasciato alle spalle è in genere accidentale, e quindi il messaggio di avviso.

Infatti, Eclipse non anche di più avanzato test per determinare i valori possibili per un'istruzione if per determinare se o non è possibile fare entrambi i percorsi.Per esempio, Eclipse sarebbe anche lamentarsi del codice morto nel seguente metodo:

public void foo() {
    System.out.println("Hello");
    boolean bool = Random.nextBoolean();
    if (bool)
        return;
    if (bool || Random.nextBoolean())
      System.out.println("World!");
}

Verrà generato un codice irraggiungibile per il secondo se l'istruzione, in quanto può la ragione che bool deve solo essere false a questo punto del codice.In un breve frammento di codice è ovvio che i due se le istruzioni sono prova la stessa cosa, ma se ci sono 10-15 righe di codice nel medio potrebbe non essere così evidente più.

Quindi, in sintesi, la differenza tra i due:è vietato dal JLS, e non lo è, ma viene rilevato da Eclipse, come un servizio per il programmatore.

Questo è quello di consentire una sorta di compilazione condizionale .
Non è un errore con if, ma il compilatore contrassegnerà un errore per while, do-while e for.
Questo è OK:

if (true) return;    // or false
System.out.println("doing something");

Questo sono errori

while (true) {
}
System.out.println("unreachable");

while (false) {
    System.out.println("unreachable");
}

do {
} while (true);
System.out.println("unreachable");

for(;;) {
}
System.out.println("unreachable");

Si è spiegato alla fine della JLS 14.21 : Dichiarazioni irraggiungibile :

  

Il razionale di questo diverso trattamento è quello di consentire ai programmatori di definire "variabili flag" come ad esempio:

 static final boolean DEBUG = false;
     

e poi scrivere codice come:

   if (DEBUG) { x=3; }
     

L'idea è che dovrebbe essere possibile modificare il valore di DEBUG da false a true o da true a false e quindi compilare il codice correttamente, senza altre modifiche al testo del programma.

Il if (true) è un po 'più sottile di "irraggiungibile"; perché quel return hard-coded farà sempre il seguente codice irraggiungibile, ma cambiando la condizione nella if potrebbe fare la seguente dichiarazione raggiungibile.

Avere un condizionale non significa che ci sia una condizione di possibilità potrebbe cambiare. Ci sono casi in cui qualcosa di più complicato di un true è tra parentesi, e non è ovvio per il lettore umano che il seguente codice è "attutito", ma gli avvisi del compilatore, quindi è in grado di mettere in guardia su di esso.

Eclipse è menzionato qui, e rende le cose sembrano un po 'più complicato per l'utente; ma in realtà sotto Eclipse è solo una (molto sofisticato) compilatore Java che accade per caratterizzare un sacco di interruttori per avvertimenti ecc che Eclipse può accendere e spegnere. In altre parole, non si ottiene proprio la vastità di diversi avvisi / errori da una compilazione javac dritto, né si deve mezzo conveniente per trasformare tutti loro acceso o spento. Ma è lo stesso affare, solo con più campane e fischietti.

Credo che un modo per un po 'in su è che il codice irraggiungibile è molto probabilmente un errore, e il JLS cerca di proteggere l'utente da tali errori.

Permettere if (true) return; è un buon modo per aggirare la limitazione JLS se si vuole realmente fare questo di proposito. Se il JLS fermato questo, sarebbe essere sempre in mezzo. Inoltre, dovrebbe anche smettere:

 public static boolean DEBUG = true; //In some global class somewhere else


 ...

 if (DEBUG) return; //in a completely unrelated class.

 ...

A causa della costante DEBUG è foderato in-tutto, e funzionalmente equivalente a semplicemente digitando una vera nel senso che se condizioni. Dal punto di vista JLS questi due casi sono molto simili.

La differenza è nella semantica tra run-time e tempo di compilazione. Nel tuo secondo esempio, il codice viene compilato in un ramo if-else nel bytecode, ed Eclipse è semplicemente abbastanza intelligente per dirvi che la parte altrimenti non potrà mai essere raggiunto in fase di esecuzione. Eclipse si avverte solo, perché è ancora codice legale.

Nel vostro primo esempio, è un errore perché il codice è illegale nella definizione di Java. Il compilatore non consente di creare il codice byte con dichiarazioni irraggiungibili.

Ho fatto alcuni cercano su Eclipse e credo che ci sono 3 tipi di movimentazione codice morto di JDK: 1) nessun avverta, 2) avvertire e 3) l'errore.

Per un "IF" Codice compilataion condizionale, JDK rilevare questo e non ha ancora segnalarlo codice tipico come morto. Per un codice morto che è causata da un flag booleano costante, JDK rilevare questo e segnalarlo al livello di allarme. Per il codice morta che è causa di flusso di controllo del programma, JDK rilevare come errore.

Di seguito è il mio tentativo:

    public class Setting {
        public static final boolean FianlDebugFlag = false;
    }


    class B {
    .....

    // no warn, it is typical "IF" conditional compilataion code
    if(Setting.FianlDebugFlag) 
        System.out.println("am i dead?");   
    if(false) 
        System.out.println("am i dead?");   


    // warn, as the dead code is caused by a constant boolean flag
    if(ret!=null && Setting.FianlDebugFlag) 
        System.out.println("am i dead?");   

    if(Setting.FinalDebug)                  
        return null;                                                            
    System.out.println("am i dea?");        

    // error, as the dead code is due to the program's control flow
    return null;
    System.out.println("am i dead");        
    }

Se si desidera ignorare l'avviso "codice morto avvertimento in Java sotto Eclipse" effettuare le seguenti operazioni all'interno di Eclipse *:

  1. Fare clic su Finestra-Preferenze-java-compilatore errori / avvisi
  2. Fai clic su "problemi di programmazione potenziali"
  3. Scegli "Ignora", il "Dead Codice esempio se (false)"
  4. Fare clic su Applica
  5. Fare clic su OK

Salvare e chiudere il vostro IDE Eclipse Quando si riapre eclissi, questi avvertimenti specifici non dovrebbero più essere incluso.

* Per questa soluzione esempio, sto utilizzando Eclipse IDE per sviluppatori Java - Versione: Mars.2 rilascio (4.5.2)

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top