Avoiding != null statements

I use object != null a lot to avoid NullPointerException .

Is there a good alternative to this?

For example:

if (someobject != null) {
    someobject.doCalc();
}

This avoids a NullPointerException , when it is unknown if the object is null or not.

Note that the accepted answer may be out of date, see https://stackoverflow.com/a/2386013/12943 for a more recent approach.


This to me sounds like a reasonably common problem that junior to intermediate developers tend to face at some point: they either don't know or don't trust the contracts they are participating in and defensively overcheck for nulls. Additionally, when writing their own code, they tend to rely on returning nulls to indicate something thus requiring the caller to check for nulls.

To put this another way, there are two instances where null checking comes up:

  • Where null is a valid response in terms of the contract; and

  • Where it isn't a valid response.

  • (2) is easy. Either use assert statements (assertions) or allow failure (for example, NullPointerException). Assertions are a highly-underused Java feature that was added in 1.4. The syntax is:

    assert <condition>
    

    or

    assert <condition> : <object>
    

    where <condition> is a boolean expression and <object> is an object whose toString() method's output will be included in the error.

    An assert statement throws an Error ( AssertionError ) if the condition is not true. By default, Java ignores assertions. You can enable assertions by passing the option -ea to the JVM. You can enable and disable assertions for individual classes and packages. This means that you can validate code with the assertions while developing and testing, and disable them in a production environment, although my testing has shown next to no performance impact from assertions.

    Not using assertions in this case is OK because the code will just fail, which is what will happen if you use assertions. The only difference is that with assertions it might happen sooner, in a more-meaningful way and possibly with extra information, which may help you to figure out why it happened if you weren't expecting it.

    (1) is a little harder. If you have no control over the code you're calling then you're stuck. If null is a valid response, you have to check for it.

    If it's code that you do control, however (and this is often the case), then it's a different story. Avoid using nulls as a response. With methods that return collections, it's easy: return empty collections (or arrays) instead of nulls pretty much all the time.

    With non-collections it might be harder. Consider this as an example: if you have these interfaces:

    public interface Action {
      void doSomething();
    }
    
    public interface Parser {
      Action findAction(String userInput);
    }
    

    where Parser takes raw user input and finds something to do, perhaps if you're implementing a command line interface for something. Now you might make the contract that it returns null if there's no appropriate action. That leads the null checking you're talking about.

    An alternative solution is to never return null and instead use the Null Object pattern:

    public class MyParser implements Parser {
      private static Action DO_NOTHING = new Action() {
        public void doSomething() { /* do nothing */ }
      };
    
      public Action findAction(String userInput) {
        // ...
        if ( /* we can't find any actions */ ) {
          return DO_NOTHING;
        }
      }
    }
    

    Compare:

    Parser parser = ParserFactory.getParser();
    if (parser == null) {
      // now what?
      // this would be an example of where null isn't (or shouldn't be) a valid response
    }
    Action action = parser.findAction(someInput);
    if (action == null) {
      // do nothing
    } else {
      action.doSomething();
    }
    

    to

    ParserFactory.getParser().findAction(someInput).doSomething();
    

    which is a much better design because it leads to more concise code.

    That said, perhaps it is entirely appropriate for the findAction() method to throw an Exception with a meaningful error message -- especially in this case where you are relying on user input. It would be much better for the findAction method to throw an Exception than for the calling method to blow up with a simple NullPointerException with no explanation.

    try {
        ParserFactory.getParser().findAction(someInput).doSomething();
    } catch(ActionNotFoundException anfe) {
        userConsole.err(anfe.getMessage());
    }
    

    Or if you think the try/catch mechanism is too ugly, rather than Do Nothing your default action should provide feedback to the user.

    public Action findAction(final String userInput) {
        /* Code to return requested Action if found */
        return new Action() {
            public void doSomething() {
                userConsole.err("Action not found: " + userInput);
            }
        }
    }
    

    If you use (or planning to use) a Java IDE like JetBrains IntelliJ IDEA, Eclipse or Netbeans or a tool like findbugs then you can use annotations to solve this problem.

    Basically, you've got @Nullable and @NotNull .

    You can use in method and parameters, like this:

    @NotNull public static String helloWorld() {
        return "Hello World";
    }
    

    or

    @Nullable public static String helloWorld() {
        return "Hello World";
    }
    

    The second example won't compile (in IntelliJ IDEA).

    When you use the first helloWorld() function in another piece of code:

    public static void main(String[] args)
    {
        String result = helloWorld();
        if(result != null) {
            System.out.println(result);
        }
    }
    

    Now the IntelliJ IDEA compiler will tell you that the check is useless, since the helloWorld() function won't return null , ever.

    Using parameter

    void someMethod(@NotNull someParameter) { }
    

    if you write something like:

    someMethod(null);
    

    This won't compile.

    Last example using @Nullable

    @Nullable iWantToDestroyEverything() { return null; }
    

    Doing this

    iWantToDestroyEverything().something();
    

    And you can be sure that this won't happen. :)

    It's a nice way to let the compiler check something more than it usually does and to enforce your contracts to be stronger. Unfortunately, it's not supported by all the compilers.

    In IntelliJ IDEA 10.5 and on, they added support for any other @Nullable @NotNull implementations.

    See blog post More flexible and configurable @Nullable/@NotNull annotations.


    If null-values are not allowed

    If your method is called externally, start with something like this:

    public void method(Object object) {
      if (object == null) {
        throw new IllegalArgumentException("...");
      }
    

    Then, in the rest of that method, you'll know that object is not null.

    If it is an internal method (not part of an API), just document that it cannot be null, and that's it.

    Example:

    public String getFirst3Chars(String text) {
      return text.subString(0, 3);
    }
    

    However, if your method just passes the value on, and the next method passes it on etc. it could get problematic. In that case you may want to check the argument as above.

    If null is allowed

    This really depends. If find that I often do something like this:

    if (object == null) {
      // something
    } else {
      // something else
    }
    

    So I branch, and do two completely different things. There is no ugly code snippet, because I really need to do two different things depending on the data. For example, should I work on the input, or should I calculate a good default value?


    It's actually rare for me to use the idiom " if (object != null && ... ".

    It may be easier to give you examples, if you show examples of where you typically use the idiom.

    链接地址: http://www.djcxy.com/p/226.html

    上一篇: 正则表达式匹配不包含单词的行吗?

    下一篇: 避免!=空语句