2008-09-08 4 views
28

Syntax, was ist der Unterschied zwischenWas ist der Sinn des finally Blocks? beiseite

try { 
} 
catch() { 
} 
finally { 
    x = 3; 
} 

und

try { 
} 
catch() { 
} 

x = 3; 

edit: in .NET 2.0?


so

try { 
    throw something maybe 
    x = 3 
} 
catch (...) { 
    x = 3 
} 

ist verhaltens äquivalent?

+0

Möglicherweise möchten Sie eine Programmiersprache angeben. Das Verhalten hängt von der Sprache ab. –

+0

Um die beste Antwort zu finden, müssen Sie klären, ob die try/catch Blöcke tatsächlich leer sind oder nicht. Wie in einer der Antworten angegeben, ist die Semantik die gleiche, wenn die try/catch-Blöcke leer sind, ansonsten sprechen unterschiedliche Antworten auf die semantischen Unterschiede an. – Kasper

+0

Ich stimme früheren Kommentaren zu, Sie müssen die tatsächliche Sprache klären und die gegebenen Antworten ernsthaft überprüfen. Die upmodded Antworten sind entweder falsch oder unvollständig. –

Antwort

32

Abhängig von der Sprache, da es einige leichte semantische Unterschiede geben könnte, aber die Idee ist, dass sie (fast) immer ausgeführt wird, auch wenn der Code im try-Block eine Ausnahme auslöst.

Wenn im zweiten Beispiel der Code im catch-Block zurückgibt oder beendet wird, wird x = 3 nicht ausgeführt. In der ersten wird es.

In der .NET-Plattform, in einigen Fällen ist die Ausführung des finally-Block wird nicht auftreten: Sicherheits Ausnahmen, Gewinde Suspensionen, Computer herunterfahren :) usw.

+2

Ich würde zu der Liste der Methoden hinzufügen, die die Ausführung des finally blockieren den * Environment.Exit * Aufruf verhindern. – Luca

0

So können Sie alle offenen Verbindungen usw. bereinigen, die im try-Block initialisiert wurden. Wenn Sie eine Verbindung geöffnet haben und dann eine Ausnahme aufgetreten ist, wurde diese Ausnahme nicht ordnungsgemäß geschlossen. Für diese Art von Szenario ist der finally-Block zuständig.

10

In Java:

Schließlich immer aufgerufen wird, unabhängig davon, ob die Ausnahme richtig abgefangen wurde(), oder in der Tat, wenn Sie überhaupt einen Haken haben.

37

Nun, für eine Sache, wenn Sie RÜCKKEHR in Ihrem try-Block, der schließlich noch laufen wird, aber Code unter dem try-catch-finally-Block wird nicht aufgelistet.

+0

Wäre das nicht die tatsächliche Antwort - mehr eine Feststellung der Tatsache ... – Ian

+0

Abgeordnet! Ich würde sagen, das ist nicht "die Antwort" .. –

+1

Sie haben Recht. Es ist eine gute Antwort, aber ich denke, es beantwortet nicht direkt die angegebene Frage. Vielleicht bedeutet das, ich hätte eine bessere Frage stellen sollen :) – Keshi

2

In dem Fall, dass der Versuch und der Fang leer sind, gibt es keinen Unterschied. Ansonsten können Sie sicher sein, dass das letztendlich ausgeführt wird.

Wenn Sie zum Beispiel eine neue Exception in Ihren catchblock werfen (retrow), dann wird die Zuweisung nur ausgeführt, wenn sie im finally-Block ist.

Normalerweise wird ein finally verwendet, um nach sich selbst aufzuräumen (DB-Verbindungen, File-Handles und ähnliches schließen).

Sie sollten nie die Kontrolle-Anweisungen verwenden (Return, break, continue) in einem schließlich, da dies ein Albtraum sein kann und deshalb schlechte Praxis

1
betrachtet wird

Der finally-Block wird immer (auch nicht wirklich genannt werden always ...), auch wenn eine Ausnahme ausgelöst oder eine return-Anweisung erreicht wird (obwohl dies sprachabhängig sein kann). Es ist eine Möglichkeit, aufzuräumen, von der Sie wissen, dass sie immer angerufen wird.

+0

Ich habe den täglichen wtf-Artikel, den du verlinkt hast, immer geliebt - besonders einer der Kommentare, die darauf hindeuten, dass wir ein magicFairyFinally brauchen, das garantiert ausgeführt wird, auch ohne Energie! –

0

@Ed, denken Sie vielleicht an etwas wie eine catch(...), die eine nicht spezifizierte Ausnahme in C++ abfängt.

Aber finally ist Code, der ausgeführt wird, egal was passiert in den catch Blöcken.

Microsoft hat eine Hilfeseite auf try-finally for C#

0

Der finally-Block in dem gleichen Umfang wie die try/catch ist, so dass Sie Zugriff auf alle Variablen innerhalb definiert haben.

Stellen Sie sich vor, Sie haben einen Datei-Handler, das ist der Unterschied, wie es geschrieben würde.

try 
{ 
    StreamReader stream = new StreamReader("foo.bar"); 
    stream.write("foo"); 
} 
catch(Exception e) { } // ignore for now 
finally 
{ 
    stream.close(); 
} 

im Vergleich zu

StreamReader stream = null; 
try 
{ 
    stream = new StreamReader("foo.bar"); 
    stream.write("foo"); 
} catch(Exception e) {} // ignore 

if (stream != null) 
    stream.close(); 

Denken Sie jedoch daran, dass alles, was im Inneren schließlich garantiert nicht laufen. Stellen Sie sich vor, Sie erhalten ein Abbruchsignal, Windows stürzt ab oder der Strom ist weg. Sich auf geschäftskritischen Code zu verlassen, ist schlecht.

+0

Bitte definieren Sie eine Sprache, da diese in Ihrer Antwort implementiert, aber nicht angegeben ist. – shsteimer

+0

Ein stackoverflow führt auch dazu, dass ein finally-Block nicht ausgeführt wird. –

+1

Ich denke, das erste Codebeispiel ist falsch (in C#) - Variablen im Block "try" deklariert sind * nicht * im Bereich in den Fang oder schließlich blockiert. Ich habe dies in einer Test-C# -Anwendung versucht und einen Kompilierungsfehler bei der finally-Block-Referenz erhalten: "Der Name 'stream' existiert im aktuellen Kontext nicht". –

0

Irgendein Code in der finally wird in der gerade im Falle einer unbehandelten Ausnahme ausgeführt. In der Regel wird der finally-Code verwendet, um lokale Deklarationen von nicht verwaltetem Code mit .dispose() zu bereinigen.

9

versuchen fangen schließlich ist ziemlich wichtig Konstrukt. Sie können sicher sein, dass selbst wenn eine Ausnahme ausgelöst wird, der Code in finally block ausgeführt wird. Bei der Verarbeitung externer Ressourcen ist es sehr wichtig, sie freizugeben. Garbage Collection wird das nicht für Sie tun. Im letzten Teil sollten Sie keine Return Anweisungen oder Ausnahmen auslösen. Es ist möglich, dies zu tun, aber es ist eine schlechte Übung und kann zu unvorhersehbaren Ergebnissen führen.

Wenn Sie dieses Beispiel versuchen:

try { 
    return 0; 
} finally { 
    return 2; 
} 

Das Ergebnis wird 2 :)

Vergleich zu anderen Sprachen sein: Return From Finally

+0

Beachten Sie, dass der Finally Block nicht immer ausgeführt wird. Ein Stackoverflow (nicht Wortspiel beabsichtigt) führt dazu, dass der finally-Block nicht ausgeführt wird. –

+1

Das Ergebnis wird 2 in Java sein. In C# kann dieser Code nicht kompiliert werden. – thorn

0

Schließlich Blöcke erlauben Sie, als Entwickler, aufzuräumen Nach dir selbst, unabhängig von den Aktionen des vorhergehenden Codes im try {} Block aufgetretene Fehler, und andere haben darauf hingewiesen, fällt fällt hauptsächlich unter den Schirm der Ressourcen zu befreien - Schließen von Zeigern/Sockets/Ergebnismengen, die Verbindungen zurück zu ein Pool etc.

@mats ist sehr richtig, dass es immer das Potenzial für „harte“ Ausfälle ist - schließlich sollten Blöcke nicht unternehmenskritischen Code enthalten, die immer transaktions innerhalb des try getan werden sollte {}

@mats wieder - Die wahre Schönheit ist, dass es Ausnahmen wieder aus den eigenen Methoden werfen kann, und garantiert immer noch, dass Sie aufzuräumen:

try 
{ 
StreamReader stream = new StreamReader("foo.bar"); 
mySendSomethingToStream(stream); 
} 
catch(noSomethingToSendException e) { 
    //Swallow this  
    logger.error(e.getMessage()); 
} 
catch(anotherTypeOfException e) { 
    //More serious, throw this one back 
    throw(e); 
} 
finally 
{ 
stream.close(); 
} 

So können wir viele Arten von Ausnahmen, verarbeitet sie anders fangen (der erste erlaubt die Ausführung für alles jenseits des try {}, der zweite kehrt effektiv zurück), aber immer sauber und ordentlich aufräumen.

4

Es gibt mehrere Dinge, die ein finally-Block nützlich machen:

  1. Wenn Sie von dem Versuch oder Catch-Blöcken zurückkehren, der finally-Block noch ausgeführt wird, kurz bevor die Steuerung zurück an die aufrufende Funktion gegeben ist
  2. Wenn innerhalb des catch-Blocks eine Ausnahmebedingung auftritt oder im try-Block ein nicht abgefangener Ausnahmetyp auftritt, wird der Code im finally-Block weiterhin ausgeführt.

Diese Blöcke sind schließlich hervorragend zum Schließen von Dateigriffen oder Sockets geeignet.

1

@iAn und @mats:

Ich würde nicht "abzureißen" alles in finally {}, das wurde im Versuch "set up" {} in der Regel. Wäre besser, die Stream-Erstellung außerhalb des try {} zu ziehen. Wenn Sie beim Erstellen eines Streams eine Ausnahme behandeln müssen, könnte dies in einem größeren Umfang geschehen.

StreamReader stream = new StreamReader("foo.bar"); 
try { 
    mySendSomethingToStream(stream); 
} 
catch(noSomethingToSendException e) { 
    //Swallow this  
    logger.error(e.getMessage()); 
} 
catch(anotherTypeOfException e) { 
    //More serious, throw this one back 
    throw(e); 
} 
finally { 
    stream.close(); 
} 
+0

Nur eine Anmerkung hier die Zeile 'werfen (e); // schreibt Stack-Trace neu. ist anders als 'throw; // wirft die ursprüngliche Ausnahme erneut " – vitule

0

In Java verwenden Sie es für alles, was Sie unabhängig von ausführen möchten, ob Sie eine „Rückkehr“ verwendet, lief gerade durch den try-Block, oder hatte eine Ausnahme abgefangen.

Zum Beispiel das Schließen einer Datenbanksitzung oder einer JMS-Verbindung oder das Zuweisen einer OS-Ressource.

Ich vermute, es ist in .NET ähnlich?