在Java中如何避免“!=null”式的判空语句?

问题描述:

我整天都是在跟Java打交道。我在Java开发中最常用的一段代码就是用object != null在使用对象之前判断是否为空。这么做是为了避免NullPointerException。但是我发现这样检测代码实在是太丑了,而且及其不可读。

那有没有一种优雅的替代方法呢?

问题补充:

再清晰化一下我的问题,我是在强调在使用对象的属性或者方法之前,确保它不为空的重要性,就像下面这段代码一样:

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

这么些我是为了避免抛NullPointerException异常,我不知道这个对象是不是空的。正由于这些判空代码,导致我的代码血花四溅,相当惨不忍睹。

最佳解答:

对于我来说,这就是一个初级开发者走向中级开发者过程中有时候都会碰到的合理问题:他们不知道也不太信任自己所使用的约定,并且过度的去检查空值情况。另外,当他们写代码的时候,总是会让方法去返回一些值,因此就可以由方法调用方去检查空值了。

换句话说,有两种情况会出现判空语句:

  • null返回值按找约定是正常的返回值
  • null返回值不是正常的返回值

第二种情况很简单。可以使用assert来判断或者是允许程序报错(即抛NullPointerException)。断言是一个被充分利用的Java特性,在1.4版本中加入了这个特性。语法如下:

assert *<condition>*

或者是

assert *<condition>* : *<object>*

object的toString()输出会被包括在错误信息中。

当判断条件为false的时候assert语句就会抛出Error(AssertionError)错误。在默认情况下,Java虚拟机是不会理会断言语句的。当需要使用此特性的时候可以给JVM虚拟机传入-ea参数来启用它。同时也可以针对单个的Java类或者是包来使用断言特性。这就意味着可以在开发测试的过程中来使用断言验证代码,而在生产环境就关闭这个特性,尽管我已经测试显示断言功能并不会对应用程序产生任何影响。

这个案例中不使用断言是可以的,因为代码本身就是会报错的,就像假如你使用断言之后一定会抛出Error错误一样。用和不用的区别就是可以尽早的去发现错误,用更有意义,更加丰富的信息来描述这个错误,这样你就可以帮助你弄清楚为什么会发生这种错误(假如这种错误你确实不想它发生)。

第一种情况就要难解释一点了。如果你对你调用的代码没有控制权的话,你就惨了。如果null返回值是正常的话,那你就必须去检查它了。

如果可以控制你调用代码(当然常常还是有控制权的),那就是另一回事儿了。还是尽量的不去使用null返回值。对于返回集合的方法很简单,只需要返回空的集合就可以了,而不是null。

对于返回值不是集合的方法,就要麻烦一点了。假如碰到下面的情况:

public interface Action {
  void doSomething();
}

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

Parse接口从标准输入中接受指令,并去执行一些操作,可能会去用这个接口实现一个命令行工具。那现在就有个约定当没找到合适的操作指令时,就返回空值。那这儿就得去验空值了。

一种可选办法就是不使用空返回值,而是空对象模式

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;
    }
  }
}

来对比下下面这两种:

Parser parser = ParserFactory.getParser();
if (parser == null) {
  // now what?
  // 这儿当然得空值判断一下啊,这儿根本就不应该出现空值
}
Action action = parser.findAction(someInput);
if (action == null) {
  // do nothing
} else {
  action.doSomething();
}
ParserFactory.getParser().findAction(someInput).doSomething();

明显下面这种写法更加简明清晰。

其实在findAction()方法中直接抛出更加有意义的错误信息是完全可以的。特别是你在依赖用户输入的应用中。对于findAction()方法来说抛出一个带有说明的异常要比光秃秃的抛出一个NullPointerException要好的多。

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

要是你觉得使用try/catch机制比较丑的话,那就给用户比较有意义的反馈。

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);
        }
    }
}

首发:译邻

原文链接: Stack Overflow 翻译: ImportNew.com - strongme
译文链接: http://www.importnew.com/13002.html
[ 转载请保留原文出处、译者和译文链接。]

关于作者: strongme

新浪微博:@奔跑的阿水哥,个人主页译邻

查看strongme的更多文章 >>



相关文章

发表评论

Comment form

(*) 表示必填项

16 条评论

  1. angiie 说道:

    文不对题啊

    Well-loved. Like or Dislike: Thumb up 9 Thumb down 2

  2. Tony 说道:

    哈哈 支持楼上 我也看得云里雾里的 最终结果是如何避免呢?

    Thumb up 2 Thumb down 0

  3. 与非 说道:

    说了等于没说一样

    Well-loved. Like or Dislike: Thumb up 7 Thumb down 0

  4. zdpg 说道:

    讲的不清楚

    Thumb up 1 Thumb down 0

  5. leoo 说道:

    用空对象啊,这不重构书上说的方法吗

    Thumb up 2 Thumb down 0

  6. cuij 说道:

    异常捕捉空指针,,我理解是这个

    Thumb up 0 Thumb down 1

  7. a 说道:

    特意跑上来说一下,这文章 讲的云里雾里的。最后还是没有总结出来什么东西。
    仅仅是解约方法的话,那么基本上人都是这么做的。

    Thumb up 2 Thumb down 1

  8. kasen 说道:

    stringutil.isnotblank(str1,str2);

    Thumb up 0 Thumb down 0

  9. itbokeyun 说道:

    避免空指针涉及到两个方面,一是返回null的方法,而是客户端代码。
    一个方法你没有办法去改写它,它就是返回null,难道我还能不检查吗?是的,你只能无奈检查,没有其他任何方法。
    如果这个方法你有权利修改,那么一切就不同了。分为两种情况,一种是返回null是表示非法,那么最好是直接抛出异常,一种是正常,返回空对象或者空集合

    Thumb up 3 Thumb down 0

  10. itbokeyun 说道:

    为什么上面会说到抛出异常呢?因为在某些场景之下,比如文章举的例子就是因为找不到对象,所以返回null,这种情况下为什么要去返回null,为什么不直接抛出找不到异常呢?
    一个要找的对象找不到,可能不是什么问题,比如在数据库中查找某个用户,结果找不到,那也没有什么,要怎么做,其实看你的理解,不过你可以这样认为,我要找的对象一定是存在的,结果不存在,所以必须抛异常,如果不是就返回空对象,反正客户端不关心这个对象存在不存在,完全可以用空对象来代替;
    不要认为避免检查空指针的方法是抛异常,而是针对具体业务它最好就是抛异常

    Well-loved. Like or Dislike: Thumb up 5 Thumb down 0

  11. 余松 说道:

    没啥意义

    Thumb up 0 Thumb down 0

  12. alextrang 说道:

    啰啰唆唆的

    Thumb up 0 Thumb down 0

  13. 李泽扬 说道:

    http://blog.csdn.net/lizeyang/article/details/40040817
    我之前也翻译过stackoverflow这个问题。大家也可以看看我翻译的版本

    另外,我的博客上还翻译了17个stackoverflow的问答。大家可以到
    http://blog.csdn.net/lizeyang/article/category/2629609
    这里看这些问答

    Thumb up 3 Thumb down 0

  14. suppender 说道:

    直接上代码撒!!!!!!!!!

    Thumb up 0 Thumb down 0

  15. aaa 说道:

    过度判断?这个说法真是奇怪。不判断会是正确的吗?

    Thumb up 0 Thumb down 0

跳到底部
返回顶部