Why Use Try {} Finally {} with an Empty Try Block

Why use try {} finally {} with an empty try block?

From http://blog.somecreativity.com/2008/04/10/the-empty-try-block-mystery/:

This methodology guards against a
Thread.Abort call interrupting the
processing. The MSDN page of
Thread.Abort says that “Unexecuted
finally blocks are executed before the
thread is aborted”. So in order to
guarantee that your processing
finishes even if your thread is
aborted in the middle by someone
calling Abort on your thread, you can
place all your code in the finally
block (the alternative is to write
code in the “catch” block to determine
where you were before “try” was
interrupted by Abort and proceed from
there if you want to).

Is there any purpose for an empty Try/Finally block?

There is no functional purpose to it — it has no effect on the run-time behavior of the program. When control leaves the try section, the program will jump to the finally section, do nothing, and then continue to whatever the next instruction should be (according to how control reached the finally statement), the same as if the try-finally block hadn't been there at all. The only difference will be that the program spends an extra moment before and after the try-finally block as it sets up and clears the control structure form the stack.

It might be that the author had a template that included a try-finally block, but that some instances of that template ended up not needing any cleanup code. Having the code fit a consistent pattern might have made certain automated tasks easier.

The try-finally block might also provide a convenient place to put a breakpoint that triggers after the protected code runs, even in the event of an exception or other premature termination.

To find out why the code has such apparently useless constructs, ask the previous author, or check the commit history.

try block with empty finally block

Using a try-finally statement without declaring a catch statement is legal.

From the JLS :

14.20.2. Execution of try-finally and try-catch-finally

A try statement with a finally block is executed by first executing
the try block. Then there is a choice:

If execution of the try block completes normally, then the finally
block is executed, and then there is a choice:

If the finally block completes normally, then the try statement
completes normally.

If the finally block completes abruptly for reason S, then the try
statement completes abruptly for reason S.

You said :

we are neither catching a exception nor cleaning up code in finally
block.
If thats the case, why does JAVA has not considered a compile time
check on this ?

What you write in the finally statement is of course at the hand of the developer.

Having a empty finally statement is useless but it is the same thing that having an empty if or for statement.

These are helpless but the compiler will not complain about it as it stays valid code in terms of compilation.

However, IDEs could emit warnings about it to point bad smells.

Empty finally{} of any use?

Empty finally block in the try-finally statement is useless. From MSDN

By using a finally block, you can clean up any resources that are
allocated in a try block, and you can run code even if an exception
occurs in the try block.

If the finally statement is empty, it means that you don't need this block at all. It can also show that your code is incomplete (for example, this is the rule used in code analysis by DevExpress).

Actually, it's pretty easy to proof that the empty finally block in the try-finally statement is useless:

Compile a simple console program with this code

static void Main(string[] args)
{
FileStream f = null;
try
{
f = File.Create("");
}
finally
{
}
}

Open the compiled dll in IL Disassembler (or any other tool that can show IL code) and you'll see that the compiler simply removed the try-finally block:

.method private hidebysig static void  Main(string[] args) cil managed
{
.entrypoint
// Code size 12 (0xc)
.maxstack 8
IL_0000: ldstr ""
IL_0005: call class [mscorlib]System.IO.FileStream [mscorlib]System.IO.File::Create(string)
IL_000a: pop
IL_000b: ret
} // end of method Program::Main

Why is try {...} finally {...} good; try {...} catch{} bad?

The big difference is that try...catch will swallow the exception, hiding the fact that an error occurred. try..finally will run your cleanup code and then the exception will keep going, to be handled by something that knows what to do with it.

Empty with/finally block in try statement

Every expression must have a result, and try ... with is no exception. The try part is evaluated and a result is obtained. But if the try part fails, the result of the with part is substituted instead.

If your try part is 0/0, then the result type of it is int. Therefore, in order for the types to match, the result of your with part should also be int. Think about what the result of the whole expression should be when the try part fails, and stick it in there:

let foo = 
try 0/0
with _ -> 42

Since you're saying that null |> ignore works, I must conclude that your try part is not in fact 0/0. The ignore function returns () (a value of type unit), so if that works for you in the with part, then your try part must be also returning unit. If that is the case, you can use () as the with part instead of null |> ignore.

let foo =
try printfn "Let's pretend that printfn may fail"
with _ -> ()

For reference, this is (roughly) how ignore is defined:

let ignore x = ()

Why are empty catch blocks a bad idea?

Usually empty try-catch is a bad idea because you are silently swallowing an error condition and then continuing execution. Occasionally this may be the right thing to do, but often it's a sign that a developer saw an exception, didn't know what to do about it, and so used an empty catch to silence the problem.

It's the programming equivalent of putting black tape over an engine warning light.

I believe that how you deal with exceptions depends on what layer of the software you are working in: Exceptions in the Rainforest.

Avoid Empty Catch Blocks When Expecting Exception

All answers given so far say that you have to live with exception catching, but there are ways to avoid exceptions at all. I demonstrate two ways, one with built-in SimpleDateFormat-API and one with using my library Time4J.

SimpleDateFormat

private static final List<SimpleDateFormat> SDF_FORMATS;

static {
String[] formats =
{
"yyyy-MM-dd'T'HH:mm:ss.SSSX",
"yyyy-MM-dd'T'HH:mm:ss.SSS-HH:mm",
"EEE MMM dd HH:mm:ss Z yyyy"
};

SDF_FORMATS =
Arrays.stream(formats)
.map(pattern -> new SimpleDateFormat(pattern, Locale.ENGLISH))
.collect(Collectors.toList());
}

public static java.util.Date parse(String input) {
for (SimpleDateFormat sdf : SDF_FORMATS) {
ParsePosition pos = new ParsePosition(0);
java.util.Date d = sdf.parse(input, pos);
if (pos.getErrorIndex() == -1) {
return d;
}
}
// log an error message
return null; // or throw an exception
}

There is an observable performance improvement although not very spectacular compared with try-catch-code. One important caveat however, this presented code is NOT thread-safe. For usage in multi-thread-environment, you have to either always instantiate a new instance of SimpleDateFormat, or you can try to use ThreadLocal to minimize such instantiations.

Time4J

private static final MultiFormatParser<Moment> MULTI_FORMAT_PARSER;

static {
String[] formats =
{
"yyyy-MM-dd'T'HH:mm:ss.SSSX",
"yyyy-MM-dd'T'HH:mm:ss.SSS-HH:mm",
"EEE MMM dd HH:mm:ss Z yyyy"
};

List<ChronoFormatter<Moment>> formatters =
Arrays.stream(formats)
.map(pattern ->
ChronoFormatter.ofMomentPattern(
pattern,
PatternType.CLDR,
Locale.ENGLISH,
Timezone.ofSystem().getID()))
.collect(Collectors.toList());
MULTI_FORMAT_PARSER = MultiFormatParser.of(formatters);
}

public static java.util.Date parse(String input) {
ParseLog plog = new ParseLog();
Moment m = MULTI_FORMAT_PARSER.parse(input, plog);
if (plog.isError()) {
// log an error message based on plog.getErrorMessage()
return null; // or throw an exception
} else {
return TemporalType.JAVA_UTIL_DATE.from(m); // converted to old API
}
}

This way is by far the quickest method to parse multiple formats. Try it out yourself (it is also possible to use Time4J on Java-6 or Android by using the version line 3.x but then you have to adjust the Java-8-streaming code in static initializer). The improvement in terms of performance is huge. And the code is also thread-safe.

General remark about your format patterns

  • I am worried about seeing the pattern "yyyy-MM-dd'T'HH:mm:ss.SSS-hh:mm" because "h" stands for 12-hour-clock (so AM/PM is missing!!!).
  • I am also worried about seeing the pattern "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" because escaping the literal "Z" in input is wrong unless you explicitly set the GMT-Zone (zero offset) on your SimpleDateFormat-instance. Background: ISO-8601 defines such a pattern and always assigns the offset UTC+00:00 to the literal "Z". By escaping you will get results based on wrong calculations (without exception or warning).

Is there a reason for using Try/Finally with ExceptionThrown variable over Try/Catch

Apparently, there are side effects to the throw; that will still remove stack trace information up through at least .Net 2. I imagine this syntax was used to work around the implementation of throw; on early versions of the framework.

This blog article gives two examples of how throw; is not equivalent to never catching an exception at all.

The question Showing stack trace of exception that is re-thrown, rather than stack trace from throw point gives a scenario whereby re-throwing the exception causes different operation in Visual Studio.



Related Topics



Leave a reply



Submit