2013-07-26 4 views
7

In diesem Java-Code,Was ist die genaue Reihenfolge der Ausführung für versuchen, fangen und schließlich?

import java.io.IOException; 

public class Copy 
{ 
    public static void main(String[] args) 
    { 
     if (args.length != 2) 
     { 
     System.err.println("usage: java Copy srcFile dstFile"); 
     return; 
     } 

     int fileHandleSrc = 0; 
     int fileHandleDst = 1; 
     try 
     { 
     fileHandleSrc = open(args[0]); 
     fileHandleDst = create(args[1]); 
     copy(fileHandleSrc, fileHandleDst); 
     } 
     catch (IOException ioe) 
     { 
     System.err.println("I/O error: " + ioe.getMessage()); 
     return; 
     } 
     finally 
     { 
     close(fileHandleSrc); 
     close(fileHandleDst); 
     } 
    } 

    static int open(String filename) 
    { 
     return 1; // Assume that filename is mapped to integer. 
    } 

    static int create(String filename) 
    { 
     return 2; // Assume that filename is mapped to integer. 
    } 

    static void close(int fileHandle) 
    { 
     System.out.println("closing file: " + fileHandle); 
    } 

    static void copy(int fileHandleSrc, int fileHandleDst) throws IOException 
    { 
     System.out.println("copying file " + fileHandleSrc + " to file " + 
         fileHandleDst); 
     if (Math.random() < 0.5) 
     throw new IOException("unable to copy file"); 

     System.out.println("After exception"); 
    } 
} 

die Ausgabe, die ich erwarte, ist

copying file 1 to file 2 
I/O error: unable to copy file 
closing file: 1 
closing file: 2 

aber manchmal bekomme ich diese erwartete Ausgabe und zu anderen Zeiten erhalte ich folgende Ausgabe:

copying file 1 to file 2 
closing file: 1 
closing file: 2 
I/O error: unable to copy file 

und manchmal sogar diese Ausgabe:

I/O error: unable to copy file 
copying file 1 to file 2 
closing file: 1 
closing file: 2 

und ob ich die erste, zweite oder dritte Ausgabe bekomme scheint zufällig bei jeder Ausführung passieren. Ich fand THIS POST, die anscheinend über das gleiche Problem spricht, aber ich verstehe immer noch nicht, warum ich manchmal 1, 2 oder 3 bekomme. Wenn ich diesen Code richtig verstehe, dann sollte Ausgabe 1 sein, was ich jedes Mal bekomme (die Ausnahme tritt auf) . Wie stelle ich sicher, dass ich Output 1 konsistent erhalte oder in der Lage bin zu sagen, wann ich Output 1 bekomme oder wann ich Output 2 oder 3 bekomme?

+0

möglich Duplikat [Random Druckauftrag für System.out & System.err ruft] (http://stackoverflow.com/questions/12594537/ random-printing-order-für-system-out-system-err-calls) – user93353

Antwort

16

Das Problem ist, dass Sie einige Ausgaben zu System.out und einige zu System.err schreiben. Dies sind unabhängige Ströme mit unabhängiger Pufferung. Der Zeitpunkt, wann sie geleert werden, ist, soweit ich weiß, nicht spezifiziert.

Kurz gesagt, wenn Sie in verschiedene Streams schreiben, können Sie nicht die Reihenfolge verwenden, in der die Ausgabe angezeigt wird, um die Reihenfolge zu bestimmen, in der die Aufrufe an println() aufgetreten sind. Beachten Sie, dass die Ausgabe an System.out immer in der erwarteten Reihenfolge angezeigt wird.

Soweit die Reihenfolge der Ausführung, der Körper der try wird zuerst ausgeführt. Wenn es eine Ausnahme auslöst, wird der Rumpf der entsprechenden catch-Klausel dann ausgeführt. Der Baustein finally wird immer zuletzt ausgeführt.

+0

aber theoretisch sollte die Reihenfolge die sein, wie in Ausgang 1 gezeigt, nicht wahr? – user13267

+1

@ user13267 - Ja. Die Reihenfolge der Ausführung ist angegeben und entspricht der Reihenfolge, die Sie für die Ausgabe erwartet haben. Machen Sie alles zu einem einzigen Stream (z. B. "System.out") und Sie sollten Ihre erwartete Reihenfolge jedes Mal sehen. Alternativ rufen Sie 'flush()' bei jedem Ausgabestrom sofort nach jedem Schreiben auf. Das sollte auch die Reihenfolge festlegen, in der die Ausgabe auf der Konsole angezeigt wird. –

+0

Ich versuchte 'System.out.flush()' und 'System.err.flush()' jedes Mal, wenn sie aufgerufen wurden, aber immer noch die Reihenfolge der Ausgabe bleibt gleich. – user13267

2

Die Sache mit der Ausnahmebehandlung mit try catch block ist, dass die Steuerung in den internen try gehen wird, wenn irgendeine Ausnahme es innerhalb catch Block bekommen wird. Aber das Steuerelement wird jedes Mal zum letzten Block gehen, wenn es ausgeführt wird.

1

Sie schreiben Ihre Fehlermeldung sowohl in stdout als auch in stderr. Sie haben unterschiedliche Puffer, es gibt also keine Garantie, dass die Ausgabe, die Sie sehen, in der gleichen Reihenfolge ist, in der Sie sie erstellt haben, zwischen den beiden Ausgabeströmen.

Da ich keine Fehler im Code sehen (obwohl die überflüssigen return; in Ihrem catch Segment in meinem Kropf ein wenig stecken), lassen Sie mich vorschlagen, dass Sie alle Ihre Nachrichten zu stderr, und sehen, ob die Nachricht schreiben, um ist etwas mehr im Einklang mit dem, was Sie erwartet haben.

1

Sie haben einen Fehler in Ihrem Beispiel, den ich entfernen würde. Sie schreiben sowohl in System.out als auch in System.err und erwarten, dass Ihre Konsole beide Streams korrekt synchronisiert. Um Nebenwirkungen zu entfernen, würde ich hier nur einen Stream verwenden.

3

Erste Try Block ausgeführt werden, wenn es Erfolg schließlich wird ausgeführt ist, wenn try Block fehlschlagen, dann wird catch ausführen und finally auszuführen. Was auch immer passieren wird schließlich Block ausgeführt werden.

Aber

Wenn Sie System.exit(0) schließlich rufen Block nicht ausgeführt

+0

Was auch immer passieren wird Block schließlich ausführen werde ich nicht zustimmen, was ist, wenn System.exit() aufgerufen wird? –

+0

@Sunny ja du bist richtig, aber ich spreche nur über diesen Fall. Wenn Sie System.exit (0) im Versuch aufrufen. Oder machen Sie etwas, das die JVM beendet oder aufhängt (wie ein Deadlock). Sonst - nein. –

Verwandte Themen