2013-08-04 19 views
6

Perché StringBuilder non stampa ciò che dovrebbe stampare in un piccolo codicePerché StringBuilder non stampa?

public final class Test1 { 

    public void test() { 
     System.out.println(setFin().toString()); 
    } 

    protected StringBuilder setFin() { 
     StringBuilder builder = new StringBuilder(); 
     try { 
      builder.append("John"); 
      return builder.append("Ibrahim"); 
     } finally { 
      System.out.println("In finaly"); // builder.append("-DarElBeida"); 
      builder = null; 
     } 
    }  

    public static void main(String args[]){ 
     new Test1().test(); 
    } 
} 

Nell'ultima istruzione eseguita in setFin() (nel blocco finally) ho assegnato null a builder, ma le mie stampe codice "In finally" e poi "JohnIbrahim" . Qualcuno può spiegarmi cosa sta succedendo qui?

+1

Questo è un codice atroce. Probabilmente, vuoi solo leggere http://docs.oracle.com/javase/tutorial/essential/exceptions/finally.html – nes1983

risposta

5

Quando c'è una dichiarazione return all'interno del blocco try, verrà eseguito il blocco finally prima di tornare effettivamente.

E il metodo non restituisce null perché l'istruzione return contiene un riferimento al reale StringBuilder oggetto , non alla variabile builder.

Impostazione builder == null non elimina il StringBuilder sé, semplicemente cade builder s' riferimento ad esso.

Questo comportamento può essere fonte di confusione. Per rendere le cose chiare che potrebbe essere utile per tornare da fuori try/catch/finally block:

StringBuilder builder = new StringBuilder(); 

try { 
    builder.append("John"); 
    builder.append("Ibrahim"); 
} finally { 
    System.out.println("In finaly"); // builder.append("-DarElBeida"); 
    builder = null; 
} 

return builder; 
+1

Penso che l'OP sia confuso sul motivo per cui non sta stampando 'null'. –

+0

no, si aspetta che stampi il nome senza "finalmente". – duffymo

+0

Penso che la confusione riguardi il motivo per cui non si stampa 'null' (cosa che la propria istruzione non spiega in realtà - il' builder = null' è "valutato prima del ritorno" quindi "dovrebbe restituire null") – Mat

3

State ritornando builder. Successivamente, imposta builder su null. Ma è già stato restituito. Non importa ciò che fai alla variabile in seguito. Il valore di ritorno è già "bloccato". Quello che potresti fare è pasticciare con l'oggetto che viene restituito. Ad esempio, builder.setLength(0) rimuoverà tutto il testo.

In teoria, si potrebbe anche return null dal blocco finally, ma che (modificando il valore di ritorno) è altamente sconsigliato.

3

ritorno valore viene valutato e memorizzato sul pila, prima dell'esecuzione del blocco finally. Si noti che il valore sullo stack è in realtà il valore del riferimento StringBuilder. Quindi, anche se si imposta la builder a null, ciò non cambia il return valore valutato già in pila. Tuttavia, se il valore di ritorno è un riferimento a un oggetto mutabile, si possono mutare l'oggetto, ed i cambiamenti saranno visibili nel return valore.

Per esempio, se si aggiunge la dichiarazione seguente nel blocco finally anziché nullifying il riferimento:

builder.append("Hrithik Roshan"); 

poi si vedrà che il contenuto del valore di ritorno.

Tuttavia, se si return il builder di nuovo, dal blocco finally, verrà a capo la precedente valutazione return valutata. Ma attenzione, non è una buona idea.

2

finally viene sempre eseguito, a meno che la JVM non si blocchi o esca prima che il blocco try termini.

Se il blocco try completa a causa di un'istruzione return, l'espressione della return viene valutata in un singolo valore prima le finally esegue blocco. Tale valore viene salvato e restituito quando il blocco finally viene completato.

Pertanto, l'assegnazione di builder = null non ha alcun effetto poiché la valutazione di builder.append("Ibrahim") è già terminata al momento dell'esecuzione di finally.

1

builder contiene un riferimento allo StringBuilder che hai creato. Quando esegui builder = null, stai impostando builder per non mantenere più quel riferimento. Lo StringBuilder stesso esiste ancora (almeno fino a quando si verifica la garbage collection).

Che cosa sta succedendo è che l'istruzione return restituisce un riferimento a StringBuilder. È non restituendo la variabile builder; sta restituendo un riferimento alla cosa a cui si riferisce builder. Quindi, anche se stai cancellando la variabile, l'istruzione return ha già un riferimento all'oggetto creato.

Se hai stampato builder nel tuo blocco finally, sarebbe nullo lì.

0

Prima esecuzione della dichiarazione return che esegue builder.append("Ibrahim") che restituisce il riferimento di StringBuilder. Il riferimento viene salvato nello stack. Quindi ha inserito il blocco finally. Hai annullato la variabile locale, ma il riferimento all'oggetto StringBuilder è passato al chiamante dopo che il metodo è effettivamente ritornato. Questo è il motivo per cui sono stati stampati tutti i valori. L'errore è che si assegna un valore allo builder nel blocco finally che non viene mai utilizzato. Lo stack mantiene il valore dell'operando dell'istruzione return prima di essere effettivamente restituito, vale a dire dopo il blocco finally. Se non si desidera restituire il riferimento dal metodo, occorre return null nel blocco finally, che sostituirà il valore nello stack.

} finally { 
    System.out.println("In finaly"); // builder.append("-DarElBeida"); 
    return null; 

}