写点什么

在 Java 中的空指针异常怎么避免?

作者:java易二三
  • 2023-07-25
    湖南
  • 本文字数:1932 字

    阅读完需:约 6 分钟

Java 中如何避免空指针异常,这也是由初级程序员成长到中级程序员的时候经常会遇到的问题。

        程序员不知道或不信任正在使用的约定,并且小心的检查着 null。还有当程序员写代码的时候,总是会依赖于通过返回空(NULL)来表明某些意义,因此需要调用者去检查 Null。

有两种空指针的检查场景:

期望的结果就是 null。

期望的结果不是 null。

第二种很简单,可以通过用 assert 或者允许程序报错,例如抛出 NullPointerException。Assertions 是一个从 Java1.4 加进来的高度未被利用的特性,语法是:

assert <condition>

        或者

assert <condition> : <object>

        condition 是一个布尔表达式,object 是一个对象(其 toString()方法的输出将会被包含在错误里)。

        校对注:我测试了下,JDK1.4 及其以上,运行前设置 vm 参数-ea

public static void main(String[] args) {String name = null;assert (name != null) : "name 为空 null";}Exception in thread "main"; java.lang.AssertionError: 变量 name 为空 nullat LogUtil.main(LogUtil.java:37)

        如果 condition 为 false 的话,assert 将会抛出一个 Error(AssertionError)。默认 Java 会忽略断言你可以通过在 JVM 中传入一个-ea 参数来启用断言。

        你可以为单独的一个包或者类启动关闭 assertions。这意味着你可以在开发和测试的时候通过断言来验证代码,在发布产品的时候关闭它,尽管我下面展示的测试中并没有因为 assertions 而损失性能。在这个代码段中不用断言也可以,因为他会运行失败的,就像加了断言一样。唯一的区别是有了断言可能会发生的更快一些,更有意义,并且会附加一些额外的信息,而这可以帮助你弄明白失败的原因。

        第一种有一点棘手。如果你对不能控制正在调用的这段代码,那你就卡住了。如果 Null 是一个合理的返回值,你就应该检查它。如果是你能够控制的代码,那就是个完全不同的故事情景了。尽量避免用 NULL 作为返回值。对于返回 Collections 的集合很容易,返回 Empty(一个空集合或者数组),而不是一直用 null 作为返回值。对于不是返回 Collections 的方法会有一点复杂。考虑下面这个例子:

public interface Action { 

     void doSomething();}public interface Parser { 

     Action findAction(String userInput);}

        Parser 采用用户的输入作为参数,然后做一些事情(例如模拟一个命令行)。现在你可能会返回 null,如果没找到对应输入的动作的话,这就导致了刚才说过的空指针检查。

        一个可选的解决方案是永远不要返回 null,而是返回一个空对象

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? 

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

        和这段:

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

        这是个更好的设计,因为足够简洁,避免了多余的判断。

        即便如此,或许比较合适的设计是:findAction()方法之恶杰抛出一个异常,其中包含一些有意义的错误信息—–特别是在这个案例中你依赖于用户的输入。

        让 findAction()方法抛出一个异常而不是简单的产生一个没有任何解释的 NullPointerException 要好得多。

try {    

        ParserFactory.getParser().findAction(someInput).doSomething();} catch(ActionNotFoundException anfe) { 

        userConsole.err(anfe.getMessage());}

        或者你认为 try/catch 的机制太丑了,你的 action 应该跟用户提供一个反馈而不是什么都不做:

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

        }    

    }}

用户头像

java易二三

关注

还未添加个人签名 2021-11-23 加入

还未添加个人简介

评论

发布
暂无评论
在Java中的空指针异常怎么避免?_指针_java易二三_InfoQ写作社区