The "using" construct looks incredibly handy for situations that require both beginning and separated end parts.
Quick example to illustrate:
using (new Tag("body")) {
Trace.WriteLine("hello!");
}
// ...
class Tag : IDisposable {
String name;
public Tag(String name) {
this.name = name;
Trace.WriteLine("<" + this.name + ">");
Trace.Indent();
}
public void Dispose() {
Trace.Unindent();
Trace.WriteLine("</" + this.name + ">")
}
}
The beginning part is defined as the constructor, the end part is the Dispose method.
However despite of being attractive this construct has a serious caveat that comes from the fact that the Dispose method is called from within a finally block. So there are 2 problems:
You should avoid throwing exceptions from the finally block because they will override the original exception that was supposed to be caught.
There is no way of knowing inside of the Dispose method if an exception was thrown earlier between "beginning" and "end" and thus there is no way of handling the "end" part accordingly.
These 2 things make using of this construct impractical which is a very sad fact. Now, my questions are:
Is my understanding of the problems right? Is this how "using" actually works?
If so, is there any way to overcome these problems and make practical use of the "using" construct other than what it was originally designed for (releasing resources and cleaning up)
In case there is no practical way for "using" to be used this way. What are the alternative approaches (to enforce the context over some code with the beginning and end parts)?
The short answer to the question “can a constructor throw an exception in Java” is yes! Of course, properly implementing exceptions in your constructors is essential to getting the best results and optimizing your code.
Example: Exception handling using try... In the example, we are trying to divide a number by 0 . Here, this code generates an exception. To handle the exception, we have put the code, 5 / 0 inside the try block. Now when an exception occurs, the rest of the code inside the try block is skipped.
Exception handling is the process of responding to unwanted or unexpected events when a computer program runs. Exception handling deals with these events to avoid the program or system crashing, and without this process, exceptions would disrupt the normal operation of a program.
An exception occurs when an unexpected event happens that requires special processing. Examples include a user providing abnormal input, a file system error being encountered when trying to read or write a file, or a program attempting to divide by zero.
Your rule #1 applies with or without using
, so the rule #2 is the real decider: opt for a try
/catch
if you must distinguish between situations when an exception has been thrown and the normal program completion.
For example, if your persistence layer may discover issues in the process of using a database connection, your connection needs to close regardless of the fact that there was an exception. In this case, the using
construct is a perfect choice.
In some cases you can set up using
specifically to detect normal completion vs. an exceptional completion. Ambient transactions provide a perfect example:
using(TransactionScope scope = new TransactionScope()) {
// Do something that may throw an exception
scope.Complete();
}
If scope
's Dispose
is called before Complete
has been called, TransactionScope
knows that an exception has been thrown, and aborts the transaction.
The intent of the using
statement and of the IDisposable
interface is for the user to dispose of unmanaged resources. These resources are usually expensive and precious, so they must be disposed of no matter what (that's why it's on the finally
). Code in finally
blocks can't even be aborted, and it can hang a whole app domain shutdown.
Now, it's very tempting to abuse using
for the purposes you're describing, and I've done that in the past. Most of the time there's no danger there. But if an unexpected exception happens, the whole state of the processing is compromised, you wouldn't necessarily want to run the end operation; so in general, don't do this.
An alternative is to use a lambda, something like this:
public interface IScopable {
void EndScope();
}
public class Tag : IScopable {
private string name;
public Tag(string name) {
this.name = name;
Trace.WriteLine("<" + this.name + ">");
Trace.Indent();
}
public void EndScope() {
Trace.Unindent();
Trace.WriteLine("</" + this.name + ">");
}
}
public static class Scoping {
public static void Scope<T>(this T scopable, Action<T> action)
where T : IScopable {
action(scopable);
scopable.EndScope();
}
}
Use it like this:
new Tag("body").Scope(_ =>
Trace.WriteLine("hello!")
);
You can also create other implementations that run certain actions based on whether exceptions were raised of not.
In Nemerle, the language can be extended with new syntax to support this.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With