Avoiding != null statements 避免判空语句

问题

来源Stack Overflow

为了避免空指针,我们常常会看到这样的语句

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

最终,项目中会存在大量判空代码,多么丑陋繁冗!如何避免这种情况?我们是否滥用了判空呢?

回答一

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

  1. Where null is a valid response in terms of the contract;
  2. Where it isn’t a valid response.

进行判空前,请区分以下两种情况:

  • null是一个有效有意义的返回值
  • null是无效有误的

(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语句(断言)或者允许失败(例如,空指针异常)。断言是jdk1.4中添加的一个未充分利用的Java特性。语法如下。

assert <condition>

or

assert <condition> : <object>

where <condition> is a boolean expression and is an object whose toString() method’s output will be included in the error.
其中<condition>是一个布尔表达式,<object>是一个对象,其toString()方法的输出将包含在错误中。

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.
如果条件不为真,断言语句将抛出一个错误(AssertionError)。默认情况下,Java会忽略断言。您可以通过将选项-ea传递给JVM来启用断言。您可以为单独的类和包启用和禁用断言。这意味着您可以在开发和测试时用断言验证代码,并在生产环境中禁用它们,尽管我的测试几乎没有显示断言对性能的影响。(注:IDEA中默认是不开启的)

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.
(1)有点难。如果你不能控制你所调用的代码,那么你就会被卡住。如果null是一个有效的响应,您必须检查它。

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.
但是,如果是由您控制的代码(通常都是这样),那么情况就完全不同了。避免使用null作为响应。对于返回集合的方法,很容易:几乎总是返回空集合(或数组),而不是返回null。return Collections.emptyList()

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.
其中Parser 接口接受原始用户输入并查找要做的事情,如果您正在为某些事情实现命令行接口的话。现在,如果没有适当的操作,您可以使契约(contract)返回null。这导致了您所说的null检查。

An alternative solution is to never return null and instead use the Null Object pattern:
另一种解决方案是从不返回null,而使用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.
也就是说,findAction()方法抛出带有有意义的错误消息的异常可能是完全合适的——尤其是在您依赖于用户输入的情况下。findAction方法抛出异常要比调用方法抛出一个简单的NullPointerException而没有任何解释要好得多。

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.
或者,如果您认为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);
        }
    }
}

总结一下:

  • null是一个有效有意义的返回值(解决:1、设计一个默认的操作 2、抛出异常)
  • null是无效有误的(解决:1、使用断言 2、允许失败)

回答二:

(回答二:没什么难词就没翻译了,有需要可以留言)
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.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值