In both cases, null is not a valid response type of ioMethod (it would only occur due to an IOException).
I beg to differ.
In the first case you have recovered from the exception. What you return now must be a valid response or you are breaking your contract. Returning null
is annoying but if it's what you return it's a valid return.
That doesn't mean after recovering you have to return null
or avoid returning at all. Your method simply returns either 1 or 0 things. We have something for that.
public void callerMethod() {
List result = ioMethod();
// call instance method of result
for (o : result) {
o.toString(); //No risk of null pointer exception
}
}
public Object ioMethod() {
List result = new ArrayList();
try {
// IO Stuff
result.add( new Object() );
}
catch (IOException e) {
e.printStackTrace();
}
return result;
}
Collections work really well when you're not sure how many of something you're going to have. If you find that too weird to look at then feel free to learn about Optional. It lets you do pretty much the same thing. The advantage is it makes it more obvious 2 and up won't be involved.
People get weird about 0 and 1. Nothingness is still a hard concept and 1 seems like it has to be special. But that doesn't mean you have to reach for null
or avoid returning.
If you insist on null
a simple if (result != null)
guard takes care of it. It's annoying but that's the deal with null
.
You can also return a null object that will quietly do nothing when asked to do something. It's a bit of work to make it but now the caller doesn't have to change. It's hands down my favorite design pattern. If you've ever used the empty string ("") you've already used a form of it.
As for your second case:
The point of throwing exceptions is to either recover by putting the system back into a known good state or to halt the system because you can't get back to a known good state.
Choosing which exception to throw is all about finding the correct recovery code to get back to a known good state.
So leaving it as a NullPointerException
is fine, and changing it is fine so long as that ensures the exception is recovered from correctly.
The problem is so damn many things can cause a NullPointerException
. Once you allow it to happen (rather than avoid it) it's fairly hard to know what exactly caused it. Which means your try
needs to be very small and call very quiet code or you're really just guessing what threw it at you.
So if you are going to rethrow make darn sure you know what you caught. Given that and I'm fine with you avoiding the checked exception nonsense as long as your code base is consistent about it.
throws IOException
? Either the method can handle the error by itself and then should return a normal object, or it can't handle the error and then shouldn't catch it.UncheckedIOException
it would not provide with any value to the domain and it's totally meaningless for upper layers, hence won't make a big deal improvement the tracking, the debugging in runtime or any possible exception handling. IMO should be the consumer who decides whether an IOException breaks the execution path with a more meaningful exception. Something like `UnableToReadObjectXException'. Whether it's checked or unchecked is up to you to decide.