Atom Feed SITE FEED   ADD TO GOOGLE READER

Calling a method that always throws

Kasper complains that it's hard to call methods that always throw. In particular, code like this won't compile because findGetter is missing a return statement:
  public Method findGetter() throws CsvException {
try {
return type.getMethod("get"
+ fieldName.substring(0, 1).toUpperCase()
+ fieldName.substring(1));
} catch(SecurityException e) {
noSuchGetter(e);
} catch (NoSuchMethodException e) {
noSuchGetter(e);
}
}

public void noSuchGetter(Exception cause) throws CsvException {
String message = String.format("Unable to lookup getter"
+ " for field %s on %s", fieldName, type.getName());
throw new CsvException(message, cause);
}

The problem is that noSuchGetter always throws, but javac doesn't consider that when building this code. Making that method private or final doesn't help -- javac does not look at the body of a method when deciding whether the callers are valid.

Adding return null; to the end of this method appeases the compiler, but it sure isn't pretty:
  public Method findGetter() throws CsvException {
try {
return type.getMethod("get"
+ fieldName.substring(0, 1).toUpperCase()
+ fieldName.substring(1));
} catch(SecurityException e) {
noSuchGetter(e);
} catch (NoSuchMethodException e) {
noSuchGetter(e);
}
return null; /* never executes! (this method never returns null.) */
}

As Kasper explains, this workaround sucks! In particular, it suggests to the code reader that he should check for null when calling this method. We need to add a big ugly comment to flag what's going on. Another workaround is to throw AssertionErrors on unreachable lines. This is an improvement but we still have dead code in our program. This line won't ever execute, adding noise to code coverage reports.

Fortunately, there's a clever fix. Declare that noSuchGetter returns a RuntimeException and prefix call to it with throw:
  public Method findGetter() throws CsvException {
try {
return type.getMethod("get"
+ fieldName.substring(0, 1).toUpperCase()
+ fieldName.substring(1));
} catch(SecurityException e) {
throw noSuchGetter(e);
} catch (NoSuchMethodException e) {
throw noSuchGetter(e);
}
}

public CsvException noSuchGetter(Exception cause)
throws CsvException {
String message = String.format("Unable to lookup getter"
+ " for field %s on %s", fieldName, type.getName());
throw new CsvException(message, cause);
}

Now the code reader can see that the noSuchGetter calls always throw without reading that method's body. And the compiler will complain if you add any code after that call. We can optionally tweak this so noSuchGetter returns CsvException rather than throwing it.

Methods that always throw should return what they throw. If the method always throws a RuntimeException, we'd return that type.
I'd argue that noSuchGetter should actually return the Exception rather than throw it. Otherwise the first line of the stack trace is misleading noise.
It doesn't matter. The stacktrace is taken when the exception is instantiated, not when it's thrown.
I don't get the point of making the method have a non-void return type. It's a lie. It never returns that type, only throws it. And then those 'throw ...' statements in the caller are not actually throwing anything, because it's the argument to the throw which actually throws the exception. It's all quite confusing.
I like it. One of my "stock methods" is a static one that wraps any exception in RuntimeException, or just re-throws if the exception is already RuntimeException. Thus my code looks a lot like yours:

try {
doSomething()
} catch (SomeException e) {
throw asRuntimeException(e);
}
The default solution has no dead code but it's confusing as-is. If I'm not used to this style of programming I'd be required to double-take back and forth before I could figure out which method threw.

I'm with steve_mcleod here, but for a different reason: it's easier to understand.
This seems like a wholly unnecessary issue in the first place.

Why would you not just have a NoSuchGetterException that extends CsvException? You'd get a place to put your message template (the constructor), and you'd get actual language support for differentiating the exception from other CsvExceptions.
Eric,

Sorry about the crappy formatting:


class AsRuntimeException extends RuntimeException {
public AsRuntimeException(Exception e) {
super(e);
if ( e instanceof RuntimeException ) {
throw (RuntimeException)e;
}
}
}
Let's imagine this is an existing API. He cannot introduce a new exception because that would change the API and could conceivably break some client code. Since Java makes him have two catch blocks, refactoring the string formatting logic into a single helper method removes some duplication.
But the 'new exception' is a subclass of the existing exception. No existing code will be broken.

You don't even need to add a 'throws' clause if you don't want to. The new exception doesn't even need to be a public or static class, it could be a private inner class-- in which case you don't get the benefit of having offered more information to the caller, but you avoid creating any dependencies on that exception going forward.

This whole idea just seems very odd to me, given that exceptions are classes and we can lean on polymorphism.
The most important point here is that there's a 'throw' statement is in the calling code. This makes the compiler happy, and it means we don't need dead code.

Whether the called method returns a RuntimeException or throws one is inconsequential. I personally prefer for it to throw. That way it allows the delegating method to return different exception types for different arguments.
this is sweet