【问题标题】:Is it a good or bad practice to check for NULL? [closed]检查 NULL 是好还是坏? [关闭]
【发布时间】:2011-12-01 19:30:40
【问题描述】:

我已经看到代码检查几乎所有应用程序层中的每个变量都不是null。我也见过几乎没有这个的代码。

if(object != null){}

检查变量是否为 NULL 的最佳实践是什么?它在哪里真正有意义,并且获得 NullPointerException 真的是一件坏事 - 所有这些 null 检查是否可能表明您的应用程序运行状况不佳?

【问题讨论】:

标签: java exception-handling programming-languages null


【解决方案1】:

以下是一些按重要性排列的最佳做法:

  1. 如果可以,请不要返回 null。例如,如果您的方法返回一个集合,则返回一个空集合而不是 null。在某些情况下,Null Object 模式可能会有所帮助。但是您必须小心,仅在 NullObject 可以提供合理的默认行为而无需额外的 if-check 的情况下使用它。
  2. 如果您的代码可以合理处理空值情况,请检查空值。如果您只是在检测到空值时抛出另一个异常,那么显式处理空值就没有什么价值了。
  3. 在函数的 javadoc 中记录返回空值的函数的所有实例。 (不幸的是,您不能真正依赖 javadoc,但它有助于维护纪律)。

【讨论】:

【解决方案2】:

明确检查 null 是个好主意,因为:

  • 您可以更早发现错误。
  • 您可以提供更具描述性的错误消息。

如果您收到NullPointerException,您可能无法准确确定哪个变量为空。即使您有引发异常的行号,该行上仍可能存在多个变量。

将这些检查放在您的公共界面中尤为重要。这是因为当您的用户提供不正确的参数时,他们应该得到一个IllegalArgumentException 告诉他们他们犯了错误。如果他们只是返回 NullPointerException,他们无法判断他们是否提供了不正确的参数,或者您的代码中是否存在错误。

【讨论】:

  • 没错。我希望运行时使用局部变量表(如果存在)和某种方法调用历史来提供更好的NullPointerException 消息。同时,显式空值检查是一种有用的替代方法。
  • 但根据 Effective Java, 2nd Edition by Joshua Bloch - Item 60:“如果调用者在某个参数中传递 null,而该参数禁止使用 null 值,则约定规定NullPointerException 被抛出,而不是 IllegalArgumentException。"
【解决方案3】:

变量应在定义时初始化,例如

Object myObject = new Object();

不是

Object myObject;
... // other code that might use myObject
myObject = new Object();

这将消除对象可能为空的大多数情况。对于对象可能为空的其他情况,按顺序检查它,但这并不意味着您必须检查每个变量。

【讨论】:

  • 空白声明(没有赋值的声明)是避免空值检查的好方法;编译器在分配值之前不允许读取变量,因此您无法检查它是否有 null 或尝试取消引用它。事实上,开发人员感觉好像他们必须初始化每个变量导致分配null(而不是有效值),这鼓励了空检查和NullPointerExceptions。要么使用空白声明,要么在提供有效初始化之前不声明。
【解决方案4】:

NullPointerExceptions 很痛苦。它们源于在集合中查找项目(缓存、映射、列表、数据库、文件系统……不胜枚举)并将空值分配给变量或访问它们。

文件系统有一个很好的方法来处理失败的引用——FileNotFoundException——但是,这会被 IOException 所掩盖,所以它不是那么明显和有用。

我发现从 Exception 扩展的这些 *NotFound 异常非常有用,并且广泛使用它们已经消除了我的大部分 NPE。

当我搜索我的数据库或从缓存中查找一个键时,我的查找器通常会抛出一个 NotFound 变体,并且在我的代码中,我知道我可以在哪里有一个通常会破坏我的代码的空值,现在我有了一个位置我可以在哪里记录或处理它。

try{
    Record r = table.where(F_ID+"=?",id);
    r.doStuff();
}catch(RecordNotFoundException e){
    LOG.info("whoops - id " + id + " not found?",e);
}

对于数组或映射等较小的东西,在检查空值之前检查长度或存在。

if(map.contains(id)){
    map.get(id).doStuff();
}else{
    LOG.info("whoops - id " + id + " not found?",e);
}

if(arr.length < index && arr[index] != null){
    arr[index].doStuff();
}else{
    LOG.info("whoops - index " + index + " not found?",e);
}

它们来自的另一个地方是来自像“Long id = null”这样的错误实例化,然后引用 id 就好像它不是 - 这只是简单的错误编码,如果你只是要初始化它,你不应该初始化它将其设置为空。通常这样做是为了让开发人员可以搜索/评估情况,然后设置值——但如果你的搜索抛出 NotFound 并且你的存在检查在 if 块中,你的逻辑元素应该阻止你访问空值——因为你必须直接分配它。

因为 NPE 通常来自错误的搜索,并且有一些方法可以规避这些失败,并结合了良好的编码实践,所以 null 检查有时被认为是坏习惯。

避免 NPE 的最佳方法是永远不要为良好的编码习惯分配空值。

所以我的回答是:如果您正在处理错误代码,请检查空值。你只需要。但如果这是你的全部代码,你永远不应该返回空值或分配它们。

【讨论】:

    猜你喜欢
    • 2011-05-04
    • 1970-01-01
    • 2010-09-05
    • 2011-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-09
    相关资源
    最近更新 更多