在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译文链接:

原文发布于微信公众号 - java一日一条(mjx_java)

原文发表时间:2016-05-02

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏逸鹏说道

必备 .NET - C# 异常处理

欢迎查看首个“必备.NET”专栏。您可以在其中了解 Microsoft .NET Framework 领域的所有最新动态,无论是 C# vNext 的最新进展(...

2786
来自专栏项勇

笔记45 | 代码性能优化建议[转]

1376
来自专栏抠抠空间

ECMAScript简介以及es6新增语法

920
来自专栏做全栈攻城狮

程序员带你十天快速入门Python,玩转电脑软件开发(四)

本系列文章立志于从一个已经习得一门编程语言的基础之上,全面介绍Python的相关开发过程和相关经验总结。本篇文章主要是基于上一篇的程序员带你十天快速入门Pyth...

892
来自专栏企鹅号快讯

R包系列——stringr包

stringr包是Hadley Wickham大神贡献的R包之一,主要用于字符串的处理。对于经常需要对数据进行预处理的分析人员来说,简直是一把“利器”,可谓是上...

3186
来自专栏java一日一条

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

我整天都是在跟Java打交道。我在Java开发中最常用的一段代码就是用object != null在使用对象之前判断是否为空。这么做是为了避免NullPoint...

1392
来自专栏Java后端技术栈

关于Java代码优化的N条建议!

本文是作者:五月的仓颉 结合自己的工作和平时学习的体验重新谈一下为什么要进行代码优化。在修改之前,作者的说法是这样的:

1222
来自专栏达摩兵的技术空间

js代码优化日常001

本文开始针对项目中总结出来的关于js基础知识的代码优化技巧进行每个细节点的分析,后续还会针对某个专题的分析。

1773
来自专栏锦小年的博客

python学习笔记7.4-内建模块base64

有时候,我们用noepad++或者记事本打开图片或者程序等文件的时候会显示大量的乱码,主要原因是这些文件编码的时候并不是字符串编码的。如果我们想把这些文件正常显...

2199
来自专栏java一日一条

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

我整天都是在跟Java打交道。我在Java开发中最常用的一段代码就是用object != null在使用对象之前判断是否为空。这么做是为了避免NullPoint...

921

扫码关注云+社区

领取腾讯云代金券