Sunday, 1 November 2009
The future of programming
Wednesday, 10 June 2009
Silence and Javascript
Monday, 6 April 2009
Resource Handling in Java: Summary
Java Resource Handling: Java 7
Java Resource Handling: Throwing the correct error
Tuesday, 31 March 2009
Resource Acquisition Is Initialization
Simple Resource Handling in Java
void foo() throws IOException {
SomeResource r = new SomeResource();
try {
//do some stuff with r
}
finally {
r.close();
}
}
This is a trivial solution, in all likelihood good enough, but it has an obvious flaw: if close() throws an exception, then this masks any exception that occured in the try block. This is not a major flaw, since the code still throws an IOException from the correct function, but it may hinder any code handling the error, or give misleading error messages or diagnostics.
For multiple resources we need nested try blocks:
void foo() throws IOException {
SomeResource r1;
try {
//open r1 etc.
AnotherResource r2;
try {
//open r2
}
finally {
r2.close();
}
finally {
r1.close();
}
}
This has the additional problem that the code is looking rather convoluted.
Resource Leak Anti-Patterns in Java
Anti-Pattern #1: Close resources in your finalizer
You put all your resources as member variables of a class, and then close them in the finalizer, just as if it were a C++ destructor.
The fundamental problem with this approach is that finalizers are only called when the VM is freeing up memory, so you're hoping that the system runs out of a plentiful resource (memory) before it runs out of a scarce resource.
Regardless of what cludges you attempt (you were hoping that System.gc() or System.runFinalization() might help out weren't you?) this approach is fatally flawed from the outset.
Anti-Pattern #2: Mishandling multiple calls to close()
The standard Java approach is to put your resource handling code in a try block, and the resource closing in a finally block.
void foo() throws IOException {
SomeResource r1;
AnotherResource r2;
try {
//open r1 & r2 and do some other stuff that might throw an exception
}
finally {
r2.close();
r1.close();
}
}
Anti-Pattern #3: Supressing close() exceptions
It's bad form to throw exceptions in a finally clause since it both masks any exception thrown in the try block and also causes the rest of the finally clause not to run, so you often see the following solution:
void foo() throws IOException {
SomeResource r = new SomeResource();
try {
//do some stuff with r
}
finally {
try{ r.close(); } catch(IOException e) { /*swallow e silently*/ }
}
}
Normally this works nicely - until close() throws an exception after the try block has been succesful, which causes the error to be silently ignored!
This leads to the worse class of defect (as per my last post) - one that easily goes undetected until it causes a failure in the real world, and also one that is very difficult to track down.
Obvious Bugs in Code
You should aim to write/design/structure your code/language/framework so that bugs are obvious.
Bugs can be spotted at various points, a slight over-simplification would be to characterise these stages as:
- Defect is seen by looking at the code
- Defect gives rise to a compiler error
- Defect gives rise to a compiler warning
- Program falls over at run-time at (or immediately after) the erroneous code.
- Erroneous behaviour caught by automated testing
- Erroneous behaviour caught later (or perhaps never)
I was reminded of this issue by considering how best to guard against resource leaks in Java. There are any number of suggestions online for how to do this, and most of the solutions make your code rather complex (so errors are easy to introduce, but hard to spot) while at the same time errors would all fall in to the "detect at runtime (hopefully by us rather than our customers)" category.
In my first set of posts I'm going to consider this issue, always keeping this fundamental rule in mind.