Viser innlegg med etiketten null. Vis alle innlegg
Viser innlegg med etiketten null. Vis alle innlegg

2007-08-26

Better exception handling

I read Karsten Wagner's Blog: Better exception handling today.

The post in essence touches three key elements of exception handling and design.

Exceptions are an equally important part of API design
Equally important as classes, method, and arguments. What exceptions are thrown where and why, and whether they should be checked, has to be carefully thought of. One should also be careful when the class hierarchy of exceptions, if one should be made at all.

For instance it isn't always the case that all exceptions should be checked (or unchecked for that matter). Be very specific on which cases which could benefit from a checked exception and thus explicit error handling on the client.

The post uses classes from java.io as an example of how not to do it. java.sql and java.remote could also be mentioned with their checked exceptions causing boilerplate code time and time again. An essential problem of their checked IOException, SQLException and RemoteException is that the exception has no way of informing the executing code whether the failure is transient or permanent, and what the recovery or restart actions could be.

For SQLException in JDK 6 this is not longer the cases, as there are now several subclasses of SQLException providing this information. See SQLNonTransientException, SQLRecoverableException, SQLTransientException, and SQLWarning for details.

Nulls considered harmful
I have written about this topic before, as others have. With the ability to declare whether a method accepts or returns nulls, static analysis tools, or even the compiler, could do checks both at compile and execution time giving better error reporting on null references. Static analysis could produce compiler errors when an argument declared not to accept nulls are served a value known to be null.

At run time checks could be added like the one added for arrays indexing, for instance in form of assertions:
assert someVarName != null : "Invalid null dereference of declared nonnull variable 'someVarName'";
These assertions could potentially be disabled by the -da command line option to the JVM.

Unchecked exceptions are better than their reputation
They are far better than many other alternatives, like SIGSEGV and core dumps, and are actually quite robust and helpful in diagnosing an error.

For most cases, a RuntimeException means you have error situations you cannot or will not handle. The default result in Java is that the stack trace is written to the console, and the executing thread stops. Whether or not the execution is restartable depends on your application. If it's a background thread responsible for some kind of periodic check, the thread will need to be rescheduled. If it's a thread responsible for serving some external request, the client could just retry the request.

Aspects to the assistance
One possible way of working around some of these issues is to put AspectJ to work.

Save state to add a restartable checkpoint
Use this to add a checkpoint before attempting an operation known to be erratic and cause inconsistent state:


@Pointcut("call(* dangerousOperation(..))")
public void dangerousOperation() {}

@Before("dangerousOperation() && this(myObject)")
public void saveState(MyClass myObject) {
  myObject.saveState();
}

@AfterThrowing(pointcut="dangerousOperation() && this(myObject)", throwing="e")
public void restoreState(MyClass myObject, SomeDangerousCheckedException e) {
  myObject.recoverState();
  log.warning("Recovered " + myObject + " from " + e);
}

Handling a certain checked exception in a common way
When using an API throwing checked exceptions you have to add boilerplate try / catch blocks around each and every call to this API, something that could be very tedious.

One solution is to use a wrapper API which catches these exceptions and provides error handling and / or unchecked exceptions. Spring JDBC does this for JDBC access.

But you can also use an aspect for this, like this one from ibm.com/developerworks/ :
public class SqlAccess {

  private Connection conn;
  private Statement stmt;

  public void doUpdate(){
    conn = DriverManager.getConnection("url for testing purposes");
    stmt = conn.createStatement();
    stmt.execute("UPDATE ACCOUNTS SET BALANCE = 0");
  }

  public static void main(String[] args)throws Exception{
    new SqlAccess().doUpdate();
  }
}

private static aspect exceptionHandling{
  declare soft : SQLException : within(SqlAccess);

  pointcut methodCall(SqlAccess accessor) : this(accessor) && call(* * SqlAccess.*(..));

  after(SqlAccess accessor) : methodCall (accessor){
    System.out.println("Closing connections.");
    if(accessor.stmt != null){
      accessor.stmt.close();
    }
    if(accessor.conn != null){
      accessor.conn.close();
    }
  }
}

2007-01-29

Null safety in Java revisited

In a previous post, I ranted on the problem of null in Java leading to NullPointerExceptions appearing when you least expect it.

Well, years have passed, and JDK versions also. JDK 7 is in the works, and null safety is one of the issues in question. As far as I can tell, three suggestions have surfaced:

  1. Symbols in relation to the type or dereference, like ? in the Nice Option Types, or # instead of .

  2. @NotNull and @Nullable annotations to method parameters, return values and instance variables. This exists in IDEA and FindBugs, and possibly Eclipse

  3. A new keyword, nonnull

In my view, the following requirements for compile-time nullable tests are most essential to focus on:

  1. The ability to declare whether a method's parameters or return value could be null and issue a compiler error if a known null is passed, and a warning if a possible null is passed

  2. Compile-time warnings for dereferencing where there's risk of null variables.



Research done on the ratio of parameters in a number of Java projects indicate that 80% of all parameters are non-nullable by design, i.e. the method intends for the parameter to be non-null. The paper continues in arguing that due to this, the default rule for references should change from nullable to non-nullable.

My suggestion is to reuse the null keyword for this in method declarations. For instance, the following method does not accept nulls in any argument, and never returns one either. If the implementation does not assert this, the compiler must issue an error:


public Object get(String query, Object value);


Conversely, the following implementation accepts null for its second argument, and might also return a null:


public null Object get(String query, null Object value);


But what's the alternative to returning a null? The NullObject design pattern has addressed this : return a special case instance which is a valid return type, but identifiable as meaning "nothing".