0

Not using UncheckedIOException, NullPointerException possible

public void callerMethod() {
    Object result = ioMethod();

    // call instance method of result
}

public Object ioMethod() {
    try {
        // IO Stuff
        return new Object();
    }
    catch (IOException e) {
        e.printStackTrace();
    }

    return null;
}

Using UncheckedIOException, NullPointerException not possible

public void callerMethod() {
    Object result = ioMethod();

    // call instance method of result
}

public Object ioMethod() {
    try {
        // IO Stuff
        return new Object();
    }
    catch (IOException e) {
        throw new UncheckedIOException(e);
    }
}

In both cases, null is not a valid response type of ioMethod (it would only occur due to an IOException). Should I throw the unchecked exception (UncheckedIOException) early in order to prevent an unchecked exception later (NullPointerException) or not try to prevent the NullPointerException?

2
  • 3
    Is there a particular reason why your method can't just be declared as 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.
    – amon
    Nov 4, 2018 at 18:32
  • I doubt of the usefulness of 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.
    – Laiv
    Nov 5, 2018 at 8:01

2 Answers 2

2

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.

1
  • 1
    Your example code is based on the assumption that callerMethod() can usefully continue its work and come to a correct solution even with arbitrary failures of ioMethod(), and I doubt that's true in the majority of caller/callee situations. Nov 4, 2018 at 21:30
4

TL;DR A method that fails (doesn't fulfill its contract) should make sure that its caller gets an exception, by either creating a new one or by letting some original exception ripple through.

Yes, throwing an UncheckedIOException is beneficial. Not so much for preventing later NullPointerExceptions, but as the preferred way of telling your caller about the ioMethod() failure.

If some methodA() calls ioMethod(), it does so for a reason, and most probably it can't fulfill its job withou success of ioMethod(). So, receiving an exception from ioMethod() automatically makes methodA() also fail with the same exception, without the need to write one specific error-handling code line in methodA().

If you choose to return null, you force methodA() to wrap the ioMethod() call in a conditional, and we all know from the bad old no-exceptions days that programmers are lazy and tend to forget about error handling.

Returning null is a valid solution if it can be viewed as a valid outcome of the method instead of a failure. And then its name should clearly indicate that (e.g. a name like tryToRead(), to remind the "lazy programmer" to deal with the null value.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.