避免!=空语句


4014

object != null要避免很多NullPointerException

有没有好的替代方法?

例如,我经常使用:

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

这将检查上述片段中NullPointerExceptionsomeobject对象。

请注意,可接受的答案可能已过期,请参阅https://stackoverflow.com/a/2386013/12943以获取最新的方法。


120
@Shervin鼓励使用null会使代码难于理解和可靠性。
汤姆·霍顿

44
提出了 Elvis运算符,但它似乎不在Java 7中。太糟糕了, ?。?:和?[]节省大量时间。
斯科特

72
不使用null优于此处的大多数其他建议。抛出异常,不返回或不允许为null。顺便说一句-'assert'关键字是无用的,因为默认情况下它被禁用。使用始终启用的故障机制
ianpojman 2012年

13
这就是为什么我现在使用Scala的原因之一。在Scala中,所有内容都不为空。如果要允许传递或返回“ nothing”,则必须显式使用Option [T]而不是仅使用T als参数或返回类型。
Thekwasti

11
@thSoft确实,Scala的出色Option类型因该语言不愿意控制或不允许而受损null。我在hackernews上提到了这一点,并被否决了,并告诉“反正没人在Scala中使用null”。猜猜是什么,我已经在同事编写的Scala中找到了null。是的,他们“做错了事”,必须对此进行教育,但事实仍然是该语言的类型系统应保护我免受此伤害,但事实并非如此:(
Andres F.

Answers:


2642

在我看来,这似乎是一个相当普遍的问题,初级和中级开发人员往往会在某个时候遇到这些问题:他们要么不知道,要么不信任他们所参与的合同,并且防御性地检查了null。此外,在编写自己的代码时,他们倾向于依靠返回空值来表示某些内容,因此要求调用者检查空值。

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

  1. 如果为null,则表示合同中的有效回复;和

  2. 无效的地方。

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

assert <condition>

要么

assert <condition> : <object>

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

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

在这种情况下,不使用断言是可以的,因为代码只会失败,这就是使用断言时会发生的情况。唯一的区别是,有了断言,它可能会更早地发生,以更有意义的方式出现,并可能带有额外的信息,这可以帮助您弄清楚为什么不期望它会发生。

(1)有点难。如果您无法控制正在调用的代码,那么您将陷入困境。如果null为有效响应,则必须检查它。

但是,如果您控制的是代码(通常是这种情况),那就是另一回事了。避免使用null作为响应。使用返回集合的方法很容易:几乎总是返回空集合(或数组)而不是null。

使用非集合,可能会更困难。以这个为例:如果您具有以下接口:

public interface Action {
  void doSomething();
}

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

在Parser中,原始的用户输入会找到要执行的操作,如果您正在为某些操作实现命令行界面的话。现在,如果没有适当的操作,您可以使合同返回null。这导致您正在谈论的空检查。

另一种解决方案是从不返回null,而使用Null Object模式

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()方法来说,抛出带有有意义的错误消息的Exception异常是完全适当的-特别是在这种情况下,您依赖于用户输入。对于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);
        }
    }
}

631
我不同意您对DO_NOTHING动作的陈述。如果find action方法找不到动作,则返回null是正确的做法。您已经在代码中“找到”了一个实际上找不到的动作,这违反了该方法的原理,从而找到了可用的动作。
MetroidFan2002

266
我同意在Java中过度使用null,尤其是在列表中。如果许多api返回一个空列表/数组/集合而不是null,那将更好。很多情况下,在应该引发异常的地方使用null。如果解析器无法解析,则应引发异常。
拉普利·安德森

92
这里的后一个示例是IIRC,即“空对象”设计模式。
史蒂文·埃弗斯

62
@Cshah(和MetroidFan2002)。很简单,将其放入合同中,然后很显然,未找到的返回动作将无济于事。如果这对调用者而言是重要的信息,则提供一种方法来发现这是未找到的操作(即,提供一种方法来检查结果是否为DO_NOTHING对象)。另外,如果通常应该找到操作,那么您仍然不应该返回null而是抛出一个专门表明该条件的异常-这仍然可以产生更好的代码。如果需要,提供一个单独的返回boolean的方法来检查是否存在动作。
凯文·布洛克

35
简洁不等于质量代码。对不起,您这么认为。您的代码隐藏了可能会出错的情况。
gshauger 2011年

634

如果使用(或计划使用)JetBrains IntelliJ IDEAEclipseNetbeans等Java IDE 或findbugs之类的工具,则可以使用注释来解决此问题。

基本上,您有@Nullable@NotNull

您可以使用in方法和参数,如下所示:

@NotNull public static String helloWorld() {
    return "Hello World";
}

要么

@Nullable public static String helloWorld() {
    return "Hello World";
}

第二个示例将无法编译(在IntelliJ IDEA中)。

helloWorld()在另一段代码中使用第一个函数时:

public static void main(String[] args)
{
    String result = helloWorld();
    if(result != null) {
        System.out.println(result);
    }
}

现在,IntelliJ IDEA编译器将告诉您该检查是无用的,因为该helloWorld()函数永远不会返回null

使用参数

void someMethod(@NotNull someParameter) { }

如果您编写如下内容:

someMethod(null);

这不会编译。

最后一个例子使用 @Nullable

@Nullable iWantToDestroyEverything() { return null; }

这样做

iWantToDestroyEverything().something();

而且您可以确定不会发生这种情况。:)

这是让编译器检查比平时更多的事情,并加强合同的一种好方法。不幸的是,并非所有编译器都支持它。

在IntelliJ IDEA 10.5及更高版本中,他们添加了对其他任何@Nullable @NotNull实现的支持。

请参阅博客文章更灵活和可配置的@ Nullable / @ NotNull批注


119
@NotNull@Nullable等NULL的含量注解的一部分JSR 305。您还可以使用它们使用诸如FindBugs之类的工具来检测潜在的问题。
Jacek S 2010年

32
我发现@NotNull@Nullable接口位于包中,这很奇怪com.sun.istack.internal。(我想我将com.sun与使用专有API的警告相关联。)
Jonik

20
代码的可移植性在jetbrains上是无效的。在绑定到ide级别之前,我会三思而后行。就像Jacek S所说的,无论我以为是JSR303,它们都是JSR的一部分。
Java Ka Baby

10
我真的不认为使用自定义编译器可以解决此问题。
Shivan Dragon

64
有关注释,其中的好处@NotNull,并@Nullable都是在源代码是由不理解他们的系统构建,他们很好地降解。因此,实际上,代码不可移植的说法可能是无效的-如果您使用支持并理解这些注释的系统,则可以从严格的错误检查中获得更多的好处,否则将得到更少的好处,但是您的代码仍应生成良好,并且您正在运行的程序的质量是相同的,因为无论如何在运行时都未强制执行这些注释。此外,所有编译器都是自定义;-)
13年

321

如果不允许使用空值

如果您的方法是从外部调用的,则应从以下内容开始:

public void method(Object object) {
  if (object == null) {
    throw new IllegalArgumentException("...");
  }

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

如果它是一个内部方法(不是API的一部分),只需证明它不能为null即可。

例:

public String getFirst3Chars(String text) {
  return text.subString(0, 3);
}

但是,如果您的方法仅将值传递给它,而下一个方法将其传递给等等,则可能会出现问题。在这种情况下,您可能需要检查上面的参数。

如果允许为null

这真的取决于。如果发现我经常这样做:

if (object == null) {
  // something
} else {
  // something else
}

因此,我分支了,做了两件事完全不同。没有丑陋的代码片段,因为我确实需要根据数据做两件事。例如,我应该在输入上工作,还是应该计算一个好的默认值?


实际上,使用成语“ if (object != null && ...” 对我来说很少见。

如果您显示了通常使用该惯用法的示例,则可能更容易为您提供示例。


94
抛出IllegalArgumentException有什么意义?我认为NullPointerException会更清楚,如果您自己不执行null检查,也会抛出该异常。我要么使用assert要么什么都不用。
Axel

23
除null以外的其他所有值都不太可能被接受。您可能有IllegalArgumentException,OutOfRageException等。有时这很有意义。其他时候,您最终创建了许多不增加任何值的异常类,那么您仅使用IllegalArgumentException。空输入有一个例外,其他所有都没有另一个例外是没有道理的。
myplacedk

7
是的,我同意失败快速的原则,但是在上面给出的示例中,该值未传递,而是在其上调用方法的对象。因此,它同样会很快失败,并且添加null检查只是抛出一个异常,而该异常会在同一时间和同一地点抛出,这似乎并没有使调试变得更容易。
Axel

8
有安全孔吗?JDK充满了这样的代码。如果您不希望用户看到堆栈跟踪,则只需禁用它们即可。没有人暗示没有记录该行为。MySQL是用C语言编写的,在该语言中取消引用空指针是未定义的行为,与抛出异常完全不同。
fgb

8
throw new IllegalArgumentException("object==null")
托尔比约恩Ravn的安徒生

238

哇,当我们有57种不同的推荐方法时,我几乎不愿意添加另一个答案NullObject pattern,但是我认为对这个问题感兴趣的某些人可能希望知道Java 7桌上有一个建议添加“空安全处理” — if-not-equal-null逻辑的简化语法。

Alex Miller给出的示例如下所示:

public String getPostcode(Person person) {  
  return person?.getAddress()?.getPostcode();  
}  

?.装置仅去参考,如果它不为空左侧标识符,否则评估表达为其余部分null。有些人,例如Java Posse成员Dick Wall和Devoxx选民确实喜欢这个提议,但也有人反对,理由是它实际上将鼓励更多地使用null哨兵价值。


更新:Project Coin下已提交了有关Java 7中的空安全运算符的正式建议语法与上面的示例略有不同,但是是相同的概念。


更新:空安全运算符建议未纳入Project Coin。因此,您不会在Java 7中看到此语法。


20
我认为这是错误的。应该有一种方法可以指定给定变量始终为非空。
托尔比约恩Ravn的安徒生

5
更新:该建议将不会使Java7。参见blogs.sun.com/darcy/entry/project_coin_final_five
鲍里斯·特尔齐奇

9
有趣的想法,但是语法的选择是荒谬的;我不希望在每个关节中都钉满问号的代码库。
罗布

7
该运算符存在于Groovy中,因此想要使用它的人仍然可以选择该运算符。
Muhd 2013年

8
这是我见过的最巧妙的想法。应该将其添加到C语法的每种明智的语言中。我宁愿到处都“钉问号”,而不要整日滚动浏览一排排的行或躲避“后卫条款”。
维克多

196

如果不允许使用未定义的值:

您可以将IDE配置为警告您有关潜在的空解除引用。例如,在Eclipse中,请参见首选项> Java>编译器>错误/警告/空分析

如果允许使用未定义的值:

如果要定义有意义的新API,请使用选项模式(功能语言可能很熟悉)。具有以下优点:

  • API中明确说明了输入或输出是否存在。
  • 编译器会强制您处理“未定义”的情况。
  • Option是monad,因此不需要冗长的null检查,只需使用map / foreach / getOrElse或类似的组合器即可安全地使用该值(示例)

Java 8具有内置Optional类(推荐);对于早期版本,有库的替代品,例如番石榴OptionalFunctionalJavaOption。但是,就像许多功能样式的模式一样,在Java中使用Option(甚至8)会产生很多样板,您可以使用不太冗长的JVM语言(例如Scala或Xtend)来减少这种样板。

如果必须处理可能返回null的API,则在Java中不能做太多事情。Xtend和Groovy具有Elvis运算符 ?:null安全取消引用运算符 ?.,但是请注意,在引用为null的情况下,此操作返回null,因此它只是“推迟”了null的正确处理。


22
确实,期权模式很棒。存在一些Java等效项。番石榴包含一个称为“可选”的有限版本,其中省略了大多数功能性内容。在Haskell中,此模式称为Maybe。
本·哈迪

9
一个可选的类将在Java中8可用
皮埃尔·亨利·

1
...而且(现在)还没有地图或flatMap:download.java.net/jdk8/docs/api/java/util/Optional.html
thSoft,2013年

3
Optional模式不能解决任何问题。而不是一个可能为空的对象,现在有两个。
Boann

1
@Boann,如果谨慎使用,可以解决所有NPE问题。如果没有,那么我想这是一个“使用”问题。
路易F.16年

189

仅在这种情况下-

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

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

将导致NullPointerExceptionif foo不存在。

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

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

42
我同意-仅在这种情况下。我无法忍受将其带入下一个不必要水平的程序员,并写出if(null!= myVar)...对我来说看起来很丑陋,没有任何目的!
亚历克斯·沃登

20
这是一般良好实践的一个特定示例,可能是最常用的示例:如果您知道,请务必这样做<object that you know that is not null>.equals(<object that might be null>);。它适用于其他方法,equals除非您知道合同且这些方法可以处理null参数。
Stef

9
这是我见到的尤达条件真正有意义的第一个示例
Erin Drummond 2013年

6
抛出NullPointerException是有原因的。之所以抛出它们,是因为对象在不应该为null的位置为null。解决此问题而不是隐藏问题是程序员的工作。
奥利弗·沃特金斯

1
Try-Catch-DoNothing隐藏了问题,这是解决该语言中缺少糖的有效做法。
echox

167

Java 8附带了新java.util.Optional类,可以解决一些问题。至少可以说,它提高了代码的可读性,并且在使用公共API的情况下,使API合同对客户开发人员更清晰。

他们像这样工作:

给定类型(Fruit)的可选对象被创建为方法的返回类型。它可以为空或包含一个Fruit对象:

public static Optional<Fruit> find(String name, List<Fruit> fruits) {
   for (Fruit fruit : fruits) {
      if (fruit.getName().equals(name)) {
         return Optional.of(fruit);
      }
   }
   return Optional.empty();
}

现在看下面的代码,我们在其中搜索Fruitfruits)列表中的给定Fruit实例:

Optional<Fruit> found = find("lemon", fruits);
if (found.isPresent()) {
   Fruit fruit = found.get();
   String name = fruit.getName();
}

您可以使用map()运算符在可选对象上执行计算或从中提取值。 orElse()可让您为缺少的值提供备用。

String nameOrNull = find("lemon", fruits)
    .map(f -> f.getName())
    .orElse("empty-name");

当然,仍然需要检查空值/空值,但是至少开发人员意识到该值可能为空,并且忘记检查的风险受到限制。

在从头开始构建的API中,Optional无论何时返回值可能为空,并且仅在不能返回时null(常规)才返回普通对象,客户端代码可能会放弃对简单对象返回值的null检查...

当然Optional也可以用作方法参数,在某些情况下,也许是比5或10个重载方法更好的指示可选参数的方法。

Optional提供了其他方便的方法,例如orElse允许使用默认值,并且ifPresent可以与lambda表达式一起使用

我邀请您阅读这篇文章(我写这个答案的主要来源),其中很好地解释NullPointerException了(通常是空指针)问题以及由此带来的(部分)解决方案OptionalJava Optional Objects


11
Google的番石榴具有Java 6+的可选实现。
布拉德利·戈特弗里德

13
这是非常强调的是,仅使用与ifPresent可选()不重要的不是增加高于正常空检查多少价值。它的核心价值在于它是可以在map / flapMap函数链中使用的monad,其实现的结果类似于其他地方提到的Groovy中的Elvis运算符。即使没有这种用法,我发现orElse / orElseThrow语法也非常有用。
Cornel Masson 2014年


4
人们为什么倾向于这样做if(optional.isPresent()){ optional.get(); }而不是optional.ifPresent(o -> { ...})
Satyendra Kumar,

1
因此,除了API契约性提示外,它实际上仅是为了满足不断享受链接方法的函数式程序员。
美眉

125

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

例:

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

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

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

StringUtils类只是众多类之一。公共领域中有很多不错的类可以进行空安全操作。

以下是一个示例,说明了在包含apache库(commons-lang-2.4.jar)时如何在JAVA中使用空vallidation。

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

如果您使用的是Spring,Spring的软件包中也具有相同的功能,请参见library(spring-2.4.6.jar)

有关如何从spring(org.springframework.util.Assert)使用此静态类的示例

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

5
您也可以使用来自Apache Commons的更通用的版本,在检查我发现的参数的方法开始时非常有用。Validate.notNull(object,“对象不能为null”); commons.apache.org/lang/apidocs/org/apache/commons/lang/…– monojohnny
2010年

@monojohnny是否将Validate使用Assert语句?我问这是因为Assert可能在JVM上激活/停用,建议不要在生产中使用。
Kurapika '17

别这么认为-如果验证失败,我相信它只会引发RuntimeException
monojohnny

96
  • 如果您认为一个对象不应该为null(或者它是一个bug),请使用断言。
  • 如果您的方法不接受空参数,请在javadoc中说出来并使用断言。

仅当您要处理对象可能为null的情况时,才需要检查对象!= null。

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



91

我喜欢“快速失败”代码。问问自己-在参数为null的情况下,您是否正在做一些有用的事情?如果在这种情况下您对代码应该做的事情没有明确的答案...即,一开始它永远不应该为null,然后忽略它并允许引发NullPointerException。调用代码对NPE的意义与IllegalArgumentException一样,但对于开发人员来说,调试和了解如果抛出NPE会导致问题出在哪里比在代码中尝试执行其他意外情况要容易得多逻辑-无论如何最终会导致应用程序失败。


2
最好使用断言,即Contract.notNull(abc,“ abc必须为非null,在xyz期间加载失败吗?”);-与if(abc!= null){throw new RuntimeException ...}相比,这是一种更紧凑的方法
ianpojman 2012年

76

Google Collections框架提供了一种实现null检查的好方法。

库类中有一个这样的方法:

static <T> T checkNotNull(T e) {
   if (e == null) {
      throw new NullPointerException();
   }
   return e;
}

用法是(与import static):

...
void foo(int a, Person p) {
   if (checkNotNull(p).getAge() > a) {
      ...
   }
   else {
      ...
   }
}
...

或在您的示例中:

checkNotNull(someobject).doCalc();

71
嗯,有什么区别?p.getAge()可以以更少的开销和更清晰的堆栈跟踪来抛出相同的NPE。我想念什么?
mysomic

15
最好在您的示例中抛出IllegalArgumentException(“ e == null”),因为它清楚地表明这是程序员意图的异常(以及足够的信息以使维护人员能够实际识别问题)。NullPointerException异常应预留的JVM,因为它当时清楚地表明,这是无意的(而且通常发生的地方难以识别)
托尔比约恩Ravn的安徒生

6
这是Google Guava的一部分。
史蒂文·贝尼特斯

32
闻起来像是对我的过度设计。只需让JVM抛出NPE,并且不要使您的代码混乱。
亚历克斯·沃登

5
我喜欢它,并通过对参数进行显式检查来打开大多数方法和构造函数。如果有错误,方法总是在前几行失败,并且我知道令人讨厌的参考文献却找不到类似的内容getThing().getItsThing().getOtherThing().wowEncapsulationIsBroken().setLol("hi");
Cory Kendall 2012年

75

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

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

如果您知道b永远不能为null,则可以交换它。对于equals最有用:而不是foo.equals("bar");更好"bar".equals(foo);


2
但是,您必须假设equals(可以是任何方法)正确处理null。实际上,这是将责任转移给其他人(或其他方法)的过程。
2013年

4
@Supericy基本上是,但是equals(或其他方法)必须进行检查null。或明确声明没有。
Angelo Fuchs

74

您可能会考虑空对象是一个错误的情况,而不是空对象模式(它有其用途)。

引发异常后,检查堆栈跟踪并解决该错误。


17
问题在于,通常您会松动上下文,因为NullPointerException不会指示WHICH变量为null,并且您可能在行中具有多个“。”操作。使用“ if(foo == null)throw new RuntimeException(” foo == null“)”可以使您明确指出错误原因,从而使堆栈跟踪给需要修复的人更多的价值。
托尔比约恩Ravn的安徒生

1
使用Andersen-我希望Java的异常系统能够包含正在处理的变量的名称,这样NullPointerExceptions不仅可以指示发生异常的行,而且还可以指示变量名。这在不混淆的软件中应该可以正常工作。
fwielstra 2011年

我没有设法得到它的工作只是还没有,但是是为了准确地解决这个问题。
MatrixFrog 2011年

问题是什么?只需在有足够上下文可用的适当级别上捕获NPE,转储上下文信息并重新抛出异常,就可以使用Java如此轻松。
user1050755 2013年

3
我有一位教授反对方法调用链接。他的理论是,应警惕超过两种方法的呼叫链。我不知道这是否是一个硬性规则,但它肯定消除了NPE堆栈跟踪的大多数问题。
RustyTheBoyRobot

74

空不是一个“问题”。它是完整的建模工具集的组成部分。软件旨在模拟世界的复杂性,而null承担了它的负担。Null表示 Java等中的“无数据”或“未知”。因此,将空值用于这些目的是适当的。我不喜欢“空对象”模式;我认为这引起了“ 谁来守护监护人 ”的问题。
如果你问我我女朋友的名字是什么,我会告诉你我没有女朋友。在Java语言中,我将返回null。一种替代方法是抛出有意义的异常,以指示某些不可能(或不可以)的问题。

  1. 对于“未知问题”,请提供“未知答案”。(从业务角度来看这是正确的,请保持null安全)在使用前在方法内部检查参数是否为null可以减轻多个调用者在调用之前对其进行检查的负担。

    public Photo getPhotoOfThePerson(Person person) {
        if (person == null)
            return null;
        // Grabbing some resources or intensive calculation
        // using person object anyhow.
    }

    Previous导致正常的逻辑流程,无法从我的照片库中获取不存在的女友的照片。

    getPhotoOfThePerson(me.getGirlfriend())

    并且它与新的Java API兼容(展望未来)

    getPhotoByName(me.getGirlfriend()?.getName())

    虽然找不到某人存储在数据库中的照片是“正常的业务流程”,但在某些其他情况下,我曾经使用如下图所示

    public static MyEnum parseMyEnum(String value); // throws IllegalArgumentException
    public static MyEnum parseMyEnumOrNull(String value);

    并且不要讨厌键入<alt> + <shift> + <j>(在Eclipse中生成javadoc)并为您的公共API编写另外三个单词。对于那些不阅读文档的人来说,这已经足够了。

    /**
     * @return photo or null
     */

    要么

    /**
     * @return photo, never null
     */
  2. 这是理论上的情况,在大多数情况下,您应该首选java null安全API(以防在未来10年内发布),但它NullPointerException是的子类Exception因此,它是一种形式Throwable,指示合理的应用程序可能想要捕获的条件(javadoc)!要使用异常的第一大优势,并且将错误处理代码与“常规”代码分开(根据Java的创建者),就我而言,适合使用catch NullPointerException

    public Photo getGirlfriendPhoto() {
        try {
            return appContext.getPhotoDataSource().getPhotoByName(me.getGirlfriend().getName());
        } catch (NullPointerException e) {
            return null;
        }
    }

    可能出现问题:

    问:如果getPhotoDataSource()返回null怎么办?
    答:这取决于业务逻辑。如果我找不到相册,则不会显示任何照片。如果未初始化appContext怎么办?此方法的业务逻辑对此提出了建议。如果相同的逻辑更严格,则引发异常,这是业务逻辑的一部分,应使用对null的显式检查(情况3)。在这里更好的新Java空安全的API配合指定要初始化的选择意味着什么,什么不意味着是快速失败的编程错误的情况下。

    问:可以执行冗余代码,并可以获取不必要的资源。
    答:如果getPhotoByName()尝试打开数据库连接,最后创建PreparedStatement并使用人员名称作为SQL参数,则可能发生。未知问题的方法给出了未知答案(案例1)在这里起作用。在获取资源之前,该方法应检查参数并在需要时返回“未知”结果。

    问:由于尝试关闭,此方法会降低性能。
    答:首先应易于理解和修改软件。只有在此之后,才有必要考虑性能!在需要的地方!(来源),还有许多其他)。

    PS。使用这种方法将是合理的,因为在某些地方使用与“常规”代码原理分开的错误处理代码是合理的。考虑下一个示例:

    public SomeValue calculateSomeValueUsingSophisticatedLogic(Predicate predicate) {
        try {
            Result1 result1 = performSomeCalculation(predicate);
            Result2 result2 = performSomeOtherCalculation(result1.getSomeProperty());
            Result3 result3 = performThirdCalculation(result2.getSomeProperty());
            Result4 result4 = performLastCalculation(result3.getSomeProperty());
            return result4.getSomeProperty();
        } catch (NullPointerException e) {
            return null;
        }
    }
    
    public SomeValue calculateSomeValueUsingSophisticatedLogic(Predicate predicate) {
        SomeValue result = null;
        if (predicate != null) {
            Result1 result1 = performSomeCalculation(predicate);
            if (result1 != null && result1.getSomeProperty() != null) {
                Result2 result2 = performSomeOtherCalculation(result1.getSomeProperty());
                if (result2 != null && result2.getSomeProperty() != null) {
                    Result3 result3 = performThirdCalculation(result2.getSomeProperty());
                    if (result3 != null && result3.getSomeProperty() != null) {
                        Result4 result4 = performLastCalculation(result3.getSomeProperty());
                        if (result4 != null) {
                            result = result4.getSomeProperty();
                        }
                    }
                }
            }
        }
        return result;
    }

    PPS。对于那些不愿投票(而不是这么快阅读文档)的人,我想说我一生中从未遇到过空指针异常(NPE)。但是这种可能性是Java创建者有意设计的,因为NPE是的子类Exception。在Java历史上有一个先例,当不是时ThreadDeathError不是因为它实际上是一个应用程序错误,而仅仅是因为它并不旨在被捕获!多少NPE适合成为一个ErrorThreadDeath!但事实并非如此。

  3. 仅当业务逻辑暗示时才检查“无数据”。

    public void updatePersonPhoneNumber(Long personId, String phoneNumber) {
        if (personId == null)
            return;
        DataSource dataSource = appContext.getStuffDataSource();
        Person person = dataSource.getPersonById(personId);
        if (person != null) {
            person.setPhoneNumber(phoneNumber);
            dataSource.updatePerson(person);
        } else {
            Person = new Person(personId);
            person.setPhoneNumber(phoneNumber);
            dataSource.insertPerson(person);
        }
    }

    public void updatePersonPhoneNumber(Long personId, String phoneNumber) {
        if (personId == null)
            return;
        DataSource dataSource = appContext.getStuffDataSource();
        Person person = dataSource.getPersonById(personId);
        if (person == null)
            throw new SomeReasonableUserException("What are you thinking about ???");
        person.setPhoneNumber(phoneNumber);
        dataSource.updatePerson(person);
    }

    如果未初始化appContext或dataSource,则未处理的运行时NullPointerException将终止当前线程,并将由Thread.defaultUncaughtExceptionHandler处理(供您定义和使用您喜欢的记录器或其他通知机制)。如果未设置,则ThreadGroup#uncaughtException将堆栈跟踪打印到系统err。应该监视应用程序错误日志,并为每个未处理的异常打开Jira问题,实际上这是应用程序错误。程序员应在初始化工作中的某处修复错误。


6
捕获NullPointerException和返回null非常难以调试。无论如何,您最终都将获得NPE,并且很难弄清楚最初是什么。
artbristol

23
如果我有声誉,我会投反对票。null不仅不是必须的,而且是类型系统中的一个漏洞。将树分配给列表是一种类型错误,因为树不是列表类型的值。按照同样的逻辑,分配null应该是类型错误,因为null不是Object类型的值,也不是任何有用的类型。即使是发明了null的人也认为这是他的“十亿美元的错误”。“可能是类型T或什么都不是的值”的概念是它自己的类型,应这样表示(例如Maybe <T>或Optional <T>)。
2013年

2
从“ Maybe <T>或Optional <T>”开始,您仍然需要像if (maybeNull.hasValue()) {...}这样编写代码,所以与有if (maybeNull != null)) {...}什么区别?
Mykhaylo Adamovych'4

1
截至“捕获NullPointerException并返回null令人难以调试。无论如何,您最终都会遇到NPE,而且真的很难弄清楚原来是什么。” 我完全同意!在这些情况下,您应该编写许多“ if”语句,或者在业务逻辑暗示数据就位的情况下抛出NPE,或者使用新Java中的空安全运算符。但是在某些情况下,我不在乎什么确切的步骤使我无效。例如,当您确实希望数据丢失时,正好在屏幕上显示之前为用户计算一些值。
Mykhaylo Adamovych

3
@MykhayloAdamovych:在您可能为null 的情况下,Maybe<T>Optional<T>不是这种情况的好处,或在T永远不应为null的情况下。如果您有一个明确表示“此值可能为null,请谨慎使用”的类型,并且始终使用并返回这种类型,那么只要您T在代码中看到一个普通的旧字符,就可以假定它永远不会为null。(当然,如果编译器可以执行的话,这将更加有用。)
cHao 2014年

71

Java 7有一个新的java.util.Objects实用程序类,在该类上有一个requireNonNull()方法。NullPointerException如果它的参数为null,则所有操作都将引发a ,但是会稍微清理一下代码。例:

Objects.requireNonNull(someObject);
someObject.doCalc();

该方法对于检查构造函数中的赋值之前最有用,其中每次使用它可以节省三行代码:

Parent(Child child) {
   if (child == null) {
      throw new NullPointerException("child");
   }
   this.child = child;
}

变成

Parent(Child child) {
   this.child = Objects.requireNonNull(child, "child");
}

9
实际上,您的示例构成了代码膨胀:第一行是多余的,因为NPE会在第二行中引发。;-)
user1050755 2013年

1
真正。一个更好的例子是第二行是doCalc(someObject)
斯图尔特(Stuart Marks)

依靠。如果您是doCalc()的作者,建议将支票放入该方法的正文中(如果可能)。然后,您很可能会调用someObject.someMethod(),在此无需再次检查null。:-)
user1050755

好吧,如果您不是的作者doCalc(),并且在给出null时它不会立即抛出NPE,则需要检查null并自己抛出NPE。那Objects.requireNonNull()是为了什么
斯图尔特(Stuart Marks)

7
这不仅仅是代码膨胀。最好预先进行检查,而不是半途而废,否则会产生副作用或使用时间/空间。
罗伯·格兰特

51

最终,完全解决此问题的唯一方法是使用另一种编程语言:

  • 在Objective-C中,您可以等同于在上调用方法nil,并且绝对不会发生任何事情。这使得大多数null检查都是不必要的,但会使错误更难以诊断。
  • 在Java派生的语言Nice中,有两种类型的所有版本:可能为空的版本和非为空的版本。您只能在非空类型上调用方法。通过显式检查null,可以将潜在为null的类型转换为非null的类型。这样可以更轻松地知道哪些地方需要空检查,哪些地方没有空检查。

哇...最正确的答案,它的答案太低了,正义在哪里?在Java中,null 始终是有效值。这是“一切都是对象”的必然结果-空是“一切”(当然,我们在这里忽略了基元,但您知道了)。我个人赞成Nice采取的方法,尽管我们可以这样做,以便可以在可为null的类型上调用方法,并将NPE提升为已检查的异常。这将必须通过编译器开关来完成,尽管它会破坏所有现有代码:(
CurtainDog 2010年

4
我对Nice不熟悉,但是Kotlin实现了相同的想法,在语言的类型系统中内置了可为null和非null的类型。比Optionals或null Object模式更简洁。
mtsahakis 18/09/17

38

确实是Java中常见的“问题”。

首先,我对此的想法:

我认为在NULL不是有效值的情况下传递NULL时“吃掉”东西是不好的。如果您没有因某种错误而退出该方法,则意味着您的方法没有出现任何错误,这是不正确的。然后,在这种情况下,您可能会返回null,然后在接收方法中再次检查null,并且它永远不会结束,最终会出现“ if!= null”等。

因此,恕我直言,null必须是一个严重错误,它会阻止进一步执行(也就是说,null不是有效值)。

我解决这个问题的方法是这样的:

首先,我遵循以下约定:

  1. 所有公共方法/ API始终检查其参数是否为null
  2. 由于所有私有方法都是受控方法,因此它们不检查是否为空(如果上面没有处理,请让它们与nullpointer异常一起死亡)
  3. 唯一不检查是否为空的方法是实用程序方法。它们是公共的,但是如果出于某种原因调用它们,则知道您传递了哪些参数。这就像试图在不提供水的情况下在水壶中烧开水一样。。。

最后,在代码中,public方法的第一行是这样的:

ValidationUtils.getNullValidator().addParam(plans, "plans").addParam(persons, "persons").validate();

请注意,addParam()返回self,因此您可以添加更多参数进行检查。

如果任何参数为null(如果选中或未选中是更多的设计/味道问题,但my 被选中),则方法validate()将引发检查。ValidationExceptionValidationException

void validate() throws ValidationException;

例如,如果“计划”为空,则该消息将包含以下文本:

参数[plans]遇到非法的参数值null

如您所见,用户消息需要addParam()方法(字符串)中的第二个值,因为即使通过反射也无法轻松检测传入的变量名(无论如何,都不是本文的主题...)。

是的,我们知道,在这一行之外,我们将不再遇到空值,因此我们可以安全地调用这些对象上的方法。

这样,代码是干净的,易于维护的和可读的。


3
绝对。仅仅引发错误和崩溃的应用程序具有更高的质量,因为毫无疑问,当它们不工作时。吞下错误的应用程序最多只能正常降级,但通常无法以难以察觉且无法修复的方式运行。当发现问题时,它们将很难调试。
保罗·杰克逊

35

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

  1. 允许异常波及-在“主循环”或某些其他管理例程中捕获异常。

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

当然也可以看看面向方面的编程-它们有插入if( o == null ) handleNull()字节码的巧妙方法。


35

除了使用之外,assert您还可以使用以下内容:

if (someobject == null) {
    // Handle null here then move on.
}

这比以下要好一些:

if (someobject != null) {
    .....
    .....



    .....
}

2
嗯,为什么呢?请不要感到任何防御,我只是想了解有关Java的更多信息:)
Matthias Meid 2010年

9
@Mudu作为一般规则,我更喜欢if语句中的表达式是更“正”的语句,而不是“负”的语句。因此,如果我看到if (!something) { x(); } else { y(); }我倾向于将其重构为if (something) { y(); } else { x(); }(尽管有人可能会认为这!= null是更积极的选择……)。但更重要的是,代码的重要部分没有包装在{}s中,并且大多数方法的缩进量减少了一级。我不知道那是否是fastcodejava的推理,但是那是我的。
MatrixFrog 2011年

1
这也是我倾向于做的事情。在我的意见书中保持代码干净。
Koray Tugay 2015年

34

只是永远不要使用null。不要这样

在我的课程中,大多数字段和局部变量都具有非null的默认值,并且我在代码的各处添加了合同声明(始终为断言),以确保这是强制执行的(因为它更简洁,比让它更具表达力)作为NPE出现,然后必须解析行号等)。

一旦采用了这种做法,我发现问题似乎已经解决。您会在开发过程中很早就偶然发现问题,并且意识到自己的弱点。更重要的是,它有助于封装不同模块的关注点,不同模块可以彼此“信任”,而不会产生更多麻烦。if = null else构造代码!

从长远来看,这是防御性的编程,可以使代码更简洁。始终对数据进行消毒,例如在此处执行严格的标准,这样问题就会消失。

class C {
    private final MyType mustBeSet;
    public C(MyType mything) {
       mustBeSet=Contract.notNull(mything);
    }
   private String name = "<unknown>";
   public void setName(String s) {
      name = Contract.notNull(s);
   }
}


class Contract {
    public static <T> T notNull(T t) { if (t == null) { throw new ContractException("argument must be non-null"); return t; }
}

合同就像微型单元测试一样,即使在生产中也总是运行,并且当发生故障时,您知道为什么,而不是随机的NPE,您必须以某种方式弄清楚。


为什么这会被否决?以我的经验,这远远优于其他方法,我想知道为什么不这样做
ianpojman 2012年

我同意,这种方法可以防止与null有关的问题,而不是通过在各处散布代码null检查来解决它们。
克里斯·布洛姆

7
这种方法的问题在于,如果从不设置名称,则其值将为“ <未知>”,其行为类似于设置值。现在,假设我需要检查名称是否从未设置过(未知),我必须对特殊值“ <未知>”进行字符串比较。
史蒂夫郭

1
史蒂夫说的真好。我通常要做的是将该值作为常量,例如public static final String UNSET =“ __ unset” ... private String field = UNSET ...然后private boolean isSet(){return UNSET.equals(field); }
ianpojman

恕我直言,这是空对象模式的实现,而您自己则是可选(合同)的实现。在持久性类上的表现如何?在这种情况下,我认为不适用。
Kurapika '17

31

Guava是Google非常有用的核心库,它具有避免空值的漂亮且有用的API。我发现UsingAndAvoidingNullExplained非常有帮助。

如Wiki中所述:

Optional<T>是用非空值替换可空T引用的一种方法。Optional可以包含非空T引用(在这种情况下,我们称该引用为“存在”),也可以不包含任何内容(在这种情况下,我们称该引用为“不存在”)。从来没有说过“包含null”。

用法:

Optional<Integer> possible = Optional.of(5);
possible.isPresent(); // returns true
possible.get(); // returns 5

@CodyGuldner对,科迪。我从链接中提供了相关报价,以提供更多背景信息。
Murat DeryaÖzen2014年

25

对于每个Java开发人员来说,这都是一个非常普遍的问题。因此,Java 8在没有混乱代码的情况下提供了官方支持来解决这些问题。

Java 8已引入java.util.Optional<T>。它是一个可能包含也可能不包含非null值的容器。Java 8提供了一种更安全的方法来处理在某些情况下其值可能为null的对象。它受HaskellScala的思想启发。

简而言之,Optional类包含一些方法来显式处理存在或不存在值的情况。但是,与null引用相比,优点是Optional <T>类迫使您考虑不存在该值的情况。因此,您可以防止意外的空指针异常。

在上面的示例中,我们有一个家庭服务工厂,该工厂将句柄返回给家庭中可用的多个设备。但是这些服务可能不可用,也不可用。这意味着它可能会导致NullPointerException。而不是添加nullif在使用任何服务之前条件,而应将其包装到Optional <Service>中。

包装到选项<T>

让我们考虑一种从工厂获取服务引用的方法。而不是返回服务引用,而是将其包装为Optional。它让API用户知道退回的服务可能会或可能不会可用/无法正常运行

public Optional<Service> getRefrigertorControl() {
      Service s = new  RefrigeratorService();
       //...
      return Optional.ofNullable(s);
   }

如您所见,Optional.ofNullable()它提供了一种包装参考的简便方法。还有另一种方法来获取Optional的引用,即Optional.empty()Optional.of()。一个用于返回一个空对象而不是重新调整null,另一个用于包装一个不可为空的对象。

那么如何避免空检查呢?

一旦包装了引用对象,Optional就提供了许多有用的方法来调用没有NPE的包装引用上的方法。

Optional ref = homeServices.getRefrigertorControl();
ref.ifPresent(HomeServices::switchItOn);

Optional.ifPresent如果给定的Consumer是非null值,则使用引用来调用它。否则,它什么都不做。

@FunctionalInterface
public interface Consumer<T>

表示一个接受单个输入参数且不返回结果的操作。与大多数其他功能接口不同,消费者应该通过副作用来操作。它是如此干净且易于理解。在上面的代码示例中,HomeService.switchOn(Service)如果Optional保持引用为非null,则被调用。

我们经常使用三元运算符检查空条件并返回替代值或默认值。Optional提供了另一种无需检查null即可处理相同条件的方法。Optional.orElse(defaultObj)如果Optional具有null值,则返回defaultObj。让我们在示例代码中使用它:

public static Optional<HomeServices> get() {
    service = Optional.of(service.orElse(new HomeServices()));
    return service;
}

现在,HomeServices.get()可以执行相同的操作,但是效果更好。它检查服务是否已经初始化。如果是,则返回相同值或创建新的新服务。可选的<T> .orElse(T)有助于返回默认值。

最后,这是我们的NPE以及空免检代码:

import java.util.Optional;
public class HomeServices {
    private static final int NOW = 0;
    private static Optional<HomeServices> service;

public static Optional<HomeServices> get() {
    service = Optional.of(service.orElse(new HomeServices()));
    return service;
}

public Optional<Service> getRefrigertorControl() {
    Service s = new  RefrigeratorService();
    //...
    return Optional.ofNullable(s);
}

public static void main(String[] args) {
    /* Get Home Services handle */
    Optional<HomeServices> homeServices = HomeServices.get();
    if(homeServices != null) {
        Optional<Service> refrigertorControl = homeServices.get().getRefrigertorControl();
        refrigertorControl.ifPresent(HomeServices::switchItOn);
    }
}

public static void switchItOn(Service s){
         //...
    }
}

完整的帖子是NPE以及Null免提代码…真的吗?


上面的代码中有一个空检查- if(homeServices != null) {可以更改为homeServices.ifPresent(h -> //action);
KrishPrabakar

23

我喜欢Nat Pryce的文章。这里是链接:

在文章中,还有一个指向Java Maybe Type的Git存储库的链接,我觉得很有趣,但是我认为单独使用它可能不会减少检查代码的膨胀。在Internet上进行了一些研究之后,我认为!=空代码膨胀主要可以通过精心设计来减少。


迈克尔·费瑟斯(Michael Feathers)撰写了简短有趣的文章,内容涉及您提到的方法:manuelp.newsblur.com/site/424
ivan.aguirre

21

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

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

现在来回答:

尝试使所有属性及其访问者尽可能地私有,或者完全避免将其公开给客户端。您当然可以在构造函数中使用参数值,但是通过减小范围,您不会让客户端类传递无效值。如果需要修改值,则始终可以创建一个new object。您只需检查构造函数中的值一次,而在其余方法中,几乎可以确定这些值不为null。

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

字节!


19

对于Java 8或更高版本,最好的替代方法是使用Optional该类。

Optional stringToUse = Optional.of("optional is there");
stringToUse.ifPresent(System.out::println);

这对于可能为空值的长链特别方便。例:

Optional<Integer> i = Optional.ofNullable(wsObject.getFoo())
    .map(f -> f.getBar())
    .map(b -> b.getBaz())
    .map(b -> b.getInt());

如何在null上引发异常的示例:

Optional optionalCarNull = Optional.ofNullable(someNull);
optionalCarNull.orElseThrow(IllegalStateException::new);

Java 7引入了该Objects.requireNonNull方法,该方法在检查某些内容是否为非空时很方便。例:

String lowerVal = Objects.requireNonNull(someVar, "input cannot be null or empty").toLowerCase();

17

我可以更一般地回答吗!

我们平时面对这个问题时,方法,我们不希望的方式得到的参数(糟糕的方法调用是程序员的故障)。例如:您期望获得一个对象,而是获得一个null。您期望得到一个至少包含一个字符的字符串,而不是一个空字符串...

因此,两者之间没有区别:

if(object == null){
   //you called my method badly!

}

要么

if(str.length() == 0){
   //you called my method badly again!
}

他们俩都想确保在执行任何其他功能之前,我们已收到有效的参数。

如其他答案中所述,为避免出现上述问题,您可以遵循“ 按合同设计”模式。请参阅http://en.wikipedia.org/wiki/Design_by_contract

要在Java中实现此模式,您可以使用javax.annotation.NotNull之类的核心Java批注,也可以使用Hibernate Validator之类的更复杂的库。

只是一个示例:

getCustomerAccounts(@NotEmpty String customerId,@Size(min = 1) String accountType)

现在,您可以安全地开发方法的核心功能,而无需检查输入参数,它们可以保护您的方法免受意外参数的影响。

您可以更进一步,确保在您的应用程序中只能创建有效的pojos。(来自休眠验证器站点的示例)

public class Car {

   @NotNull
   private String manufacturer;

   @NotNull
   @Size(min = 2, max = 14)
   private String licensePlate;

   @Min(2)
   private int seatCount;

   // ...
}

javax根据定义,不是 “核心Java”。
托马斯2015年

17

我高度无视建议在每种情况下使用null对象的答案。这种模式可能破坏合同,并越来越深地掩埋问题,而不是解决它们,更不用说使用不当会产生另一堆样板代码,需要将来进行维护。

实际上,如果从方法返回的内容可以为null,并且调用代码必须对此做出决定,则应该有一个更早的调用来确保状态。

还请记住,如果不加小心使用,空对象模式将占用大量内存。为此-NullObject的实例应在所有者之间共享,而不是每个所有者的唯一实例。

我也不建议使用这种模式,在这种模式中类型应该是原始类型表示形式-像不是标量的数学实体:向量,矩阵,复数和POD(普通旧数据)对象,它们是用来保存状态的以Java内置类型的形式。在后一种情况下,您最终将以任意结果调用getter方法。例如,NullPerson.getName()方法应返回什么?

值得考虑这样的情况以避免产生荒谬的结果。


使用“ hasBackground()”的解决方案有一个缺点-它不是线程安全的。如果需要调用两个方法而不是一个方法,则需要在多线程环境中同步整个序列。
pkalinow '16

@pkalinow您做了一个人为的示例,只是指出此解决方案有一个缺点。如果代码不打算在多线程应用程序中运行,那么就没有缺点。我可能会给您90%的不是线程安全的代码。我们不是在这里谈论代码的这一方面,而是在谈论设计模式。多线程本身就是一个主题。
luke1985 '16

当然,在单线程应用程序中这不是问题。我提供了该评论,因为有时这是一个问题。
pkalinow

@pkalinow如果您仔细研究该主题,您会发现Null Object设计模式无法解决多线程问题。因此无关紧要。老实说,我已经找到了适合这种模式的地方,所以我的原始答案实际上是错误的。
luke1985 '16

16
  1. 切勿将变量初始化为null。
  2. 如果不可能使用(1),请将所有集合和数组初始化为空的集合/数组。

用您自己的代码执行此操作,可以避免!=空检查。

大多数时候,空检查似乎可以保护集合或数组的循环,因此只需将它们初始化为空,就不需要任何空检查。

// Bad
ArrayList<String> lemmings;
String[] names;

void checkLemmings() {
    if (lemmings != null) for(lemming: lemmings) {
        // do something
    }
}



// Good
ArrayList<String> lemmings = new ArrayList<String>();
String[] names = {};

void checkLemmings() {
    for(lemming: lemmings) {
        // do something
    }
}

这样做的开销很小,但是对于更简洁的代码和更少的NullPointerExceptions而言,这是值得的。



3
+1这我同意。您永远不应返回一半的初始化对象。Jaxb相关代码和Bean代码对此不是问题。这是不好的做法。应该初始化所有集合,并且所有对象都应该存在(理想情况下)没有空引用。考虑其中具有集合的对象。检查对象是否不为null,集合是否不为null以及该集合不包含null的对象是不合理且愚蠢的。
ggb667 2013年

15

对于大多数开发人员来说,这是最常见的错误。

我们有多种方法可以解决此问题。

方法1:

org.apache.commons.lang.Validate //using apache framework

notNull(对象对象,字符串消息)

方法二:

if(someObject!=null){ // simply checking against null
}

方法3:

@isNull @Nullable  // using annotation based validation

方法4:

// by writing static method and calling it across whereever we needed to check the validation

static <T> T isNull(someObject e){  
   if(e == null){
      throw new NullPointerException();
   }
   return e;
}

广告。4.它不是很有用-当您检查指针是否为空时,您可能想在其上调用一个方法。在null上调用方法会产生相同的行为-NullPointerException。
pkalinow '16

11
public static <T> T ifNull(T toCheck, T ifNull) {
    if (toCheck == null) {
           return ifNull;
    }
    return toCheck;
}

2
这种方法有什么问题,我认为@tltester只想提供默认值(如果它为null),这是有道理的。
索耶

1
Apache commons-lang:中有这样一种方法ObjectUtils.defaultIfNull()。还有一个更一般的:ObjectUtils.firstNonNull(),可以用来实施降级策略:firstNonNull(bestChoice, secondBest, thirdBest, fallBack);
ivant
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.