Should I throw a NullPointerException explicitly or let Java do it for me?

前端 未结 6 2139
一整个雨季
一整个雨季 2021-02-19 13:23

As the title says, I am wondering what the best practice is regarding the throwing of NullPointerExceptions. Specifically, if I have an external library function that can return

相关标签:
6条回答
  • 2021-02-19 13:27

    Very interesting question.

    I think some kind of ProblemCreatingSynthesizerException should be thrown by that method, instead of returning null.

    I'd put the null check and throw a NPE or other custom ProblemWithSynthesizerException of your own (Sun, for some reason, conceived this Exception as a JVM-ish exception, not meant to be used by the programmer. This is what it says in some certification tutorials and books. However, I don't buy that, and some often I throw my own NPEs in my libraries).

    0 讨论(0)
  • 2021-02-19 13:34

    I dont like having null be a valid return value, even in "exceptional circumstances". So I take yet another approach.

    In your case I'd annotate the method createSynthesizer(...) with @NotNull (@NotNull is an amazing annotation). Instead of an NPE, I'd get an IllegalStateException as soon as createSynthesizer(...) would want to return null.

    You'd get a:

    java.lang.IllegalStateException: @NotNull method .../.../createSynthetiser(...) must not return null
    

    There are several benefits to this approach:

    • both NullPointerException and IllegalStateException extends RuntimeException so you're not fundamentally changing your program

    • the exception shall be thrown immediately where the error happens (not later on, once you either check/throw yourself or once you try to dereference null)

    • you don't need to bother writing the if ... == null / throw part anymore.

    As a, gigantic, added benefit some IDE (like IntelliJ IDEA) will warn you in real-time about probable @NotNull violations.

    0 讨论(0)
  • 2021-02-19 13:36

    I'd say that you should never explicitly create a NullPointerException and instead use an exception type that more clearly describes the situation. In your case, I'd say IllegalStateException would fit the situation "wrong setup of the system, and pretty unrecoverable from at runtime". Or you could create your own ComponentMissingException. In cases where a required method parameter is null, IllegalArgumentException is typically used.

    0 讨论(0)
  • 2021-02-19 13:38

    Regarding the original code:

    synthesizer = Central.createSynthesizer(generalDesc);
    
    if (synthesizer == null) {
        // (1) throw NPE explicitly
        throw new NullPointerException("No general domain synthesizer found.");
    }
    
    // (2) let the JVM throw the NPE when dereferencing
    synthesizer.allocate();
    

    My take is that throwing the NPE as shown here is OK, but with tremendous caveats. The caveat under which this is OK is only if the NPE ctor argument is a sufficiently descriptive (and hopefully unique) message (one hopefully pulled out of a constant or resource set.) Another caveat is that your main priority to get things out of the door, and such casea, this would count as an acceptable quick-n-dirty solution.

    Under ideal circumstances, my preference is use exceptions specific to invalid configurations. And when those are not available, to either use NPE subclasses (like Apache Commons Math's NullArgumentException) or the old exceptions found in Apache Common Lang 2.x. That is my position for NPEs and IllegalArgument-type exceptions. I don't necessarily agree with Apache Common Lang's position on preferring to use the standard JDK exceptions over more semantically-relevant exceptions. But that's just me, and I'm getting off the tangent...

    ... so back to the original question. As I said before, throwing the NPE like that is ok in a quick-n-dirty way (when you are in one of those "need to get that sh1t out!!(10+1)" kind of situations.

    Notice, however, this is a NPE caused by an application or systems configuration problem, as you correctly identified it. That is, the NPE is not the root cause, by a symptom or effect of another error condition (in this case, a configuration or environment error.)

    Central.createSynthesizer returns null if it cannot find a suitable synthesizer, which is most often caused by a missing speech.properties file. So it's a matter of wrong setup of the system, and pretty unrecoverable from at runtime, rather than circumstances that need to be handled programmatically.

    Unrecoverability is not a certainty. An application could have other ways to handle this situation programmatically.

    As such, I believe throwing a NullPointerException is a valid response, since it indicates a bug (not in the code but in the deployment of the software). But since the synthesizer object is dereferenced in the very next statement, should I just let the JVM throw the NPE for me and save the null check?

    I wouldn't do that, even under get-that-sh1t-out-of-the-door circumstances. The NPE thrown that way by the JVM will have a very uninformative message in it. In general, check everything for NULL and throw a descriptive exception (NPE or otherwise) when you encounter one.

    Don't check for NPEs if you can guarantee that whatever you are getting (parameters for example) has already been checked for NPEs already (in a design-by-contract kind of way.)

    Addendum: Considering that speech.properties gets loaded when the JVM starts needs to exist on the filesystem in (normally) "user.home" or "java.home/lib", it is puzzling that createSynthesizer doesn't straight up throw an NPE (which is what I had written originally in a Freudian slip) when it fails to find it but returns null instead.

    Again, that's because the response to that situation is application specific. The application might decide to go on a limping mode with partial functionality instead of crashing and burning to the ground. If createSynthesizer were to throw a NPE, then the API designer forces the application designer to adopt the later behavior, or go to somewhat greater lengths to implement a "limping" mode of operations (by having to use a catch/try instead of a simple if-null test.

    I think that throwing a NullPointerException is the right thing to do here, because it indicates an actual bug in the deployment of the software.

    Again, only if the NPE is a quick-n-dirty solution to get things out of the door. Under those conditions, it is ok. A better approach is to identify what this is, a configuration error.

    So it would be better to have application specific exceptions like IllegalConfigurationException or InvalidConfigurationException or IncompleteConfigurationException. I don't like using java.lang.IllegalStateException for such cases, because this is not caused by calling something in an invalid state. The invalid state got reached because of an invalid configuration. Maybe I'm playing semantic games, but there is something icky about using IllegalStateException in such cases (that's just me being subjective, I know.)

    0 讨论(0)
  • 2021-02-19 13:40

    I have never used Java, but if I were using the application, I would want to see an error message than a crash. NullPointerException sounds like a bug in the code to me - I would rather see an error message with directions on how to properly configure the program, or at least a hyperlink to a web page that had such directions.

    If I were a user and saw that a program had terminated with NullPointerException, I would file a bug against the program, or at least be confused as to what to do next.

    0 讨论(0)
  • 2021-02-19 13:41

    In your case: neither. Check for null and throw more meaningful exception, not NPE.

    In general - if NPE should not occur, don't test for it explicitly, Java will do it for you. Less tests to write, less code to read, less complexity to analyze.

    However if null is expected test it as soon as possible and interpret accordingly. Otherwise NullPointerException will occur somewhere later in different line/method, making it harder to debug the real problem.

    0 讨论(0)
提交回复
热议问题