Java 避免 != null 语句

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/271526/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 12:19:56  来源:igfitidea点击:

Avoiding != null statements

javaobjectnullpointerexceptionnull

提问by Goran Martinic

I use object != nulla lot to avoid NullPointerException.

我用object != null了很多来避免NullPointerException.

Is there a good alternative to this?

有什么好的替代方法吗?

For example I often use:

例如我经常使用:

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

This checks for a NullPointerExceptionfor the someobjectobject in the above snippet.

此检查一个NullPointerException用于someobject在上述片段对象。

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

请注意,已接受的答案可能已过时,请参阅https://stackoverflow.com/a/2386013/12943了解更新的方法。

采纳答案by cletus

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:

换句话说,有两种情况会出现空检查:

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

  2. Where it isn't a valid response.

  1. 如果 null 是合同中的有效响应;和

  2. 如果它不是有效的响应。

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

(2) 容易。使用assert语句(断言)或允许失败(例如 NullPointerException)。断言是 1.4 中添加的一项未被充分利用的 Java 功能。语法是:

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.

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

An assertstatement throws an Error(AssertionError) if the condition is not true. By default, Java ignores assertions. You can enable assertions by passing the option -eato 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.

一个assert语句抛出一个ErrorAssertionError如果条件是不正确的)。默认情况下,Java 忽略断言。您可以通过将选项传递-ea给 JVM来启用断言。您可以为单个类和包启用和禁用断言。这意味着您可以在开发和测试时使用断言验证代码,并在生产环境中禁用它们,尽管我的测试表明断言几乎没有性能影响。

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.

但是,如果您确实控制了代码(而且情况经常如此),那么情况就不同了。避免使用空值作为响应。使用返回集合的方法,很容易:几乎一直返回空集合(或数组)而不是空值。

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 获取原始用户输入并找到要做的事情,也许如果您正在为某事实现命令行界面。现在,如果没有适当的操作,您可以制定返回 null 的合同。这导致您正在谈论的空检查。

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

另一种解决方案是永远不要返回 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;
    }
  }
}

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

回答by Jim Nelson

Rather than Null Object Pattern -- which has its uses -- you might consider situations where the null object is a bug.

而不是空对象模式——它有它的用途——你可能会考虑空对象是一个错误的情况。

When the exception is thrown, examine the stack trace and work through the bug.

抛出异常时,检查堆栈跟踪并解决错误。

回答by pgras

  • If you consider an object should not be null (or it is a bug) use an assert.
  • If your method doesn't accept null params say it in the javadoc and use an assert.
  • 如果您认为一个对象不应该为空(或者它是一个错误),请使用断言。
  • 如果您的方法不接受空参数,请在 javadoc 中说出来并使用断言。

You have to check for object != null only if you want to handle the case where the object may be null...

仅当您想处理对象可能为空的情况时,您才必须检查 object != null ...

There is a proposal to add new annotations in Java7 to help with null / notnull params: http://tech.puredanger.com/java7/#jsr308

建议在 Java7 中添加新注释以帮助处理 null / notnull 参数:http://tech.puredanger.com/java7/#jsr308

回答by Johannes Schaub - litb

Sometimes, you have methods that operate on its parameters that define a symmetric operation:

有时,您有一些方法对其定义对称操作的参数进行操作:

a.f(b); <-> b.f(a);

If you know b can never be null, you can just swap it. It is most useful for equals: Instead of foo.equals("bar");better do "bar".equals(foo);.

如果你知道 b 永远不能为空,你可以交换它。它对 equals 最有用:而不是foo.equals("bar");better do "bar".equals(foo);

回答by javamonkey79

Depending on what kind of objects you are checking you may be able to use some of the classes in the apache commons such as: apache commons langand apache commons collections

根据您检查的对象类型,您可以使用 apache commons 中的一些类,例如:apache commons langapache commons collections

Example:

例子:

String foo;
...
if( StringUtils.isBlank( foo ) ) {
   ///do something
}

or (depending on what you need to check):

或(取决于您需要检查的内容):

String foo;
...
if( StringUtils.isEmpty( foo ) ) {
   ///do something
}

The StringUtils class is only one of many; there are quite a few good classes in the commons that do null safe manipulation.

StringUtils 类只是众多类之一;公地中有很多很好的类可以进行空安全操作。

Here follows an example of how you can use null vallidation in JAVA when you include apache library(commons-lang-2.4.jar)

下面是一个示例,说明当您包含 apache 库(commons-lang-2.4.jar)时,如何在 JAVA 中使用空验证

public DOCUMENT read(String xml, ValidationEventHandler validationEventHandler) {
    Validate.notNull(validationEventHandler,"ValidationHandler not Injected");
    return read(new StringReader(xml), true, validationEventHandler);
}

And if you are using Spring, Spring also has the same functionality in its package, see library(spring-2.4.6.jar)

如果你使用的是 Spring,Spring 在它的包中也有同样的功能,参见 library(spring-2.4.6.jar)

Example on how to use this static classf from spring(org.springframework.util.Assert)

关于如何从 spring(org.springframework.util.Assert) 使用这个静态 classf 的示例

Assert.notNull(validationEventHandler,"ValidationHandler not Injected");

回答by myplacedk

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 objectis not null.

然后,在该方法的其余部分,您将知道它object不为空。

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

如果它是一个内部方法(不是 API 的一部分),只需记录它不能为空,就是这样。

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

如果允许 null

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 && ...".

我其实很少用“ if (object != null && ...”这个成语。

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

如果您展示了您通常在何处使用该习语的示例,则可能更容易为您提供示例。

回答by xtofl

Asking that question points out that you may be interested in error handling strategies. Your team's architect should decide how to work errors. There are several ways to do this:

问这个问题表明您可能对错误处理策略感兴趣。您团队的架构师应该决定如何处理错误。做这件事有很多种方法:

  1. allow the Exceptions to ripple through - catch them at the 'main loop' or in some other managing routine.

    • check for error conditions and handle them appropriately
  1. 允许异常波动 - 在“主循环”或其他一些管理例程中捕获它们。

    • 检查错误情况并适当处理它们

Sure do have a look at Aspect Oriented Programming, too - they have neat ways to insert if( o == null ) handleNull()into your bytecode.

当然也看看面向方面的编程 - 他们有很好的方法来插入if( o == null ) handleNull()你的字节码。

回答by xtofl

Wherever you pass an array or a Vector, initialise these to empty ones, instead of null. - This way you can avoid lots of checking for null and all is good :)

无论您在何处传递数组或向量,都将它们初始化为空的,而不是 null。- 这样你就可以避免大量检查空值,一切都很好:)

public class NonNullThing {

   Vector vectorField = new Vector();

   int[] arrayField = new int[0];

   public NonNullThing() {

      // etc

   }

}

回答by echox

Only for this situation -

只针对这种情况——

Not checking if a variable is null before invoking an equals method (a string compare example below):

在调用 equals 方法之前不检查变量是否为空(下面的字符串比较示例):

if ( foo.equals("bar") ) {
 // ...
}

will result in a NullPointerExceptionif foodoesn't exist.

将导致NullPointerExceptioniffoo不存在。

You can avoid that if you compare your Strings like this:

如果您String像这样比较s ,则可以避免这种情况:

if ( "bar".equals(foo) ) {
 // ...
}

回答by OscarRyz

I've tried the NullObjectPatternbut for me is not always the best way to go. There are sometimes when a "no action" is not appropiate.

我已经尝试过,NullObjectPattern但对我来说并不总是最好的方法。有时“不采取行动”是不合适的。

NullPointerExceptionis a Runtime exceptionthat means it's developers fault and with enough experience it tells you exactly where is the error.

NullPointerException是一个运行时异常,这意味着它是开发人员的错,并且有足够的经验它会告诉您错误的确切位置。

Now to the answer:

现在回答:

Try to make all your attributes and its accessors as private as possible or avoid to expose them to the clients at all. You can have the argument values in the constructor of course, but by reducing the scope you don't let the client class pass an invalid value. If you need to modify the values, you can always create a new object. You check the values in the constructor only onceand in the rest of the methods you can be almost sure that the values are not null.

尽量使您的所有属性及其访问器尽可能私密,或者根本避免将它们暴露给客户端。当然,您可以在构造函数中使用参数值,但通过缩小范围,您不会让客户端类传递无效值。如果您需要修改这些值,您可以随时创建一个新的object. 您只检查构造函数中的值一次,而在其余方法中,您几乎可以确定这些值不为空。

Of course, experience is the better way to understand and apply this suggestion.

当然,经验是理解和应用这个建议的更好方法。

Byte!

字节!