I understand the concept of try: except: block or try: except: else: but I don't seem to understand purpose of the finally: block.Is there a difference between:
try:
*try something*
except:
*catch and handle error
finally:
*continue rest of the script*And:
try:
*try something*
except:
*catch and handle error
*continue rest of the script without 'finally' block*I suppose there must be some difference,but I can't find any
exception - What is the point of finally in a try catch/except finally statement - Stack Overflow
python - Order of execution in try except finally - Stack Overflow
language agnostic - Why use try … finally without a catch clause? - Software Engineering Stack Exchange
try... except... finally!
Videos
You just need two try/finally blocks:
Screen.Cursor:= crHourGlass;
try
Obj:= TSomeObject.Create;
try
// do something
finally
Obj.Free;
end;
finally
Screen.Cursor:= crDefault;
end;
The guideline to follow is that you should use finally rather than except for protecting resources. As you have observed, if you attempt to do it with except then you are forced to write the finalising code twice.
Once you enter the try/finally block, the code in the finally section is guaranteed to run, no matter what happens between try and finally.
So, in the code above, the outer try/finally ensures that Screen.Cursor is restored in the face of any exceptions. Likewise the inner try/finally ensures that Obj is destroyed in case of any exceptions being raised during its lifetime.
If you want to handle an exception then you need a distinct try/except block. However, in most cases you should not attempt to handle exceptions. Just let it propagate up to the main application exception handler which will show a message to the user.
If you handle the exception to low down the call chain then the calling code will not know that the code it called has failed.
As others have explained, you need to protect the cursor change with try finally block. To avoid writing those I use code like this:
unit autoCursor;
interface
uses Controls;
type
ICursor = interface(IInterface)
['{F5B4EB9C-6B74-42A3-B3DC-5068CCCBDA7A}']
end;
function __SetCursor(const aCursor: TCursor): ICursor;
implementation
uses Forms;
type
TAutoCursor = class(TInterfacedObject, ICursor)
private
FCursor: TCursor;
public
constructor Create(const aCursor: TCursor);
destructor Destroy; override;
end;
{ TAutoCursor }
constructor TAutoCursor.Create(const aCursor: TCursor);
begin
inherited Create;
FCursor := Screen.Cursor;
Screen.Cursor := aCursor;
end;
destructor TAutoCursor.Destroy;
begin
Screen.Cursor := FCursor;
inherited;
end;
function __SetCursor(const aCursor: TCursor): ICursor;
begin
Result := TAutoCursor.Create(aCursor);
end;
end.
Now you just use it like
uses
autoCursor;
procedure TForm1.Button1Click(Sender: TObject);
var
Obj: TSomeObject;
begin
__SetCursor(crHourGlass);
Obj:= TSomeObject.Create;
try
// do something
finally
Obj.Free;
end;
end;
and Delphi's reference counted interface mechanism takes care of restoring the cursor.
The purpose of a finally block is to ensure that code gets run in three circumstances which would not very cleanly be handled using "catch" blocks alone:
- If code within the
tryblock exits via fallthrough orreturn - If code within a
catchblock either rethrows the caught exception, or--accidentally or intentionally--ends up throwing a new one. - If the code within the
tryblock encounters an exception for which thetryhas nocatch.
One could copy the finally code before every return or throw, and wrap catch blocks within their own try/catch to allow for the possibility of an accidental exception occurring, but it's far easier to forgo all that and simply use a finally block.
BTW, one thing I wish language designers would include would be an exception argument to the finally block, to deal with the case where one needs to clean up after an exception but still wants it to percolate up the call stack (e.g. one could wrap the code for a constructor in such a construct, and Dispose the object under construction if the constructor was going to exit with an exception).
To make it even easier to understand:
try { //a }
catch { //b }
//c
In above code, //c won't execute:
- if you use "return" inside the try block. **
- if you use "return" inside the catch block. **
- if you raise any exception inside the catch block.
- if your try block raises an exception that can't be caught by your catch block.
While in below code:
try { //a }
catch { //b }
finally { //c }
//c will execute no matter what.
It depends on whether you can deal with the exceptions that can be raised at this point or not.
If you can handle the exceptions locally you should, and it is better to handle the error as close to where it is raised as possible.
If you can't handle them locally then just having a try / finally block is perfectly reasonable - assuming there's some code you need to execute regardless of whether the method succeeded or not. For example (from Neil's comment), opening a stream and then passing that stream to an inner method to be loaded is an excellent example of when you'd need try { } finally { }, using the finally clause to ensure that the stream is closed regardless of the success or failure of the read.
However, you will still need an exception handler somewhere in your code - unless you want your application to crash completely of course. It depends on the architecture of your application exactly where that handler is.
The finally block is used for code that must always run, whether an error condition (exception) occurred or not.
The code in the finally block is run after the try block completes and, if a caught exception occurred, after the corresponding catch block completes. It is always run, even if an uncaught exception occurred in the try or catch block.
The finally block is typically used for closing files, network connections, etc. that were opened in the try block. The reason is that the file or network connection must be closed, whether the operation using that file or network connection succeeded or whether it failed.
Care should be taken in the finally block to ensure that it does not itself throw an exception. For example, be doubly sure to check all variables for null, etc.