Viser innlegg med etiketten java. Vis alle innlegg
Viser innlegg med etiketten java. 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-08-06

Nyttig søkemotor for javadoc

jdksearch.com er en Google Custom Search som raskt og effektivt gir deg muligheten for å søke i javadoc på java.sun.com.

Du kan også filtrere resultatene på JDK versjon slik at du raskt og enkelt kan finne den relevante dokumentasjonen.

Anbefales!

2007-08-05

Oppdatert XmlEditor

Jeg har oppdatert XPath XML-editoren til også å støtte sletting av elementer. Dette er for eksempel nyttig dersom du ønsker å flytte versjonsnummeret til dependencyManagement i topp-POM for prosjektet.

For å angi at du vil slette en node bruker du følgende syntaks: /xpath:=&

Hvorfor &? Fordi det er ugyldig i XML og dermed ikke har noen reell mening.

Du finner siste versjon her : xmleditor.tar.bz2

2007-07-05

XPath-basert XML-editor

Jeg hadde en spesifikk kløe i dag : bulk-redigering av Maven POM-filer for å endre innholdet i et bestemt element.

Så jeg laget XmlEditor for å sette innholdet i noder plukket ut ved hjelp av XPath.

Dersom du for eksempel skal endre versjonsnummeret i alle POM-filer til en gitt versjon, kan du gjøre følgende:

java XmlEditor /project/version:=9.9.9 `find . -name pom.xml`


Eller for å oppdatere til siste versjon av jUnit og log4j :
java XmlEditor \
"//dependency[artifactId='junit']/version:=4.3.1" \
"//dependency[artifactId='log4j']/version:=1.2.14" \
`find . -name pom.xml`


Det er bare fantasien og hva man får til med XPath som begrenser hva man kan gjøre med denne..

2007-07-03

Hvordan lage pointcut på arvet metode

Vi forsøkte å lage et pointcut som skulle treffe på en metode som klassen vi var interessert i ikke implementerte selv, men arvet fra superklasse.

Den vanlige execution(* the.package.name.SubClass.method(..)) fungerte ikke, og AspectJ-kompilatoren spyttet ut merkelige meldinger.

Løsningen er å bruke this() matcheren:

  execution(* method(type1, type2, *)) && 
this(the.package.name.SubClass)


Takk til Kaare for tips.

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".

2007-01-12

Exceptionhåndtering i Java

One of the most important architectural decisions a Java developer can make is how to use the Java exception model. Java exceptions have been the subject of considerable debate in the community. Some have argued that checked exceptions in the Java language are an experiment that failed. This article argues that the fault does not lie with the Java model, but with Java library designers who failed to acknowledge the two basic causes of method failure. It advocates a way of thinking about the nature of exceptional conditions and describes design patterns that will help your design.

Effective Java Exceptions

Blogged with Flock

2007-01-09

Ytelse på forskjellige JDK-versjoner

Et eksempel på hvor store endringer det har vært i ytelse gjennom de siste to JDK-generasjonene fra Atlassian Developer Blog: JIRA uberbox:

The other bit that I found interesting was the performance increases between JDK 1.4, JDK 1.5 and JDK 1.6:

* JIRA Functional Tests for Enterprise JDK 1.4: 25 mins
* JIRA Functional Tests for Enterprise JDK 1.5: 19 mins
* JIRA Functional Tests for Enterprise JDK 1.6: 16 mins

Antitestdrevet utvikling

Testdrevet utvikling sier man skal skrive tester for ønsket atferd til koden, og at kode som feiler, skal rettes straks.

Men hva dersom feilretting utsettes av ulike årsaker? Skal testen feile? Dette gjør det vanskeligere å skille kjente feil fra uventede feil.

Charles Miller foreslår et alternativ i The Fishbowl: Revenge of the Anti-Test!:

The solution, perhaps, is the anti-test. Write a test that verifies the bug. One that goes green when the application is misbehaving in the way that you expect it to misbehave. Make sure you annotate it with the issue that it's verifying. That way your continuous integration environment will let you know immediately if something's suddenly worse than it was before.

Or perhaps, when something is spontaneously better.