【问题标题】:Java: Is it ok to set Integer = null?Java:设置 Integer = null 可以吗?
【发布时间】:2011-01-08 20:41:34
【问题描述】:

如果参数存在于数据库中,我有一个函数会返回一个 ID 号。如果不是,则返回 null。这是在乞求空指针异常吗?不允许使用负 id 编号,但我认为让不存在的参数返回 null 而不是像 -1 这样的错误代码会更清楚。你怎么看?

private Integer tidOfTerm(String name) throws SQLException {
    String sql = "SELECT tid FROM term_data WHERE name = ?";
    PreparedStatement prep = conn.prepareStatement(sql);
    prep.setString(1, name);
    ResultSet result = prep.getResultSet();

    if (result.next()) {
        return result.getInt("tid");
    }

    return null; // TODO: is this begging for a null pointer exception?
}

【问题讨论】:

  • 你的 return 语句可以更短: return result.next() ?结果.getInt("tid") ?空;
  • @Willi - 更短!= 更具可读性
  • 大体上同意,但在上面的例子中会更好。

标签: java integer autoboxing error-code


【解决方案1】:

这是完全合法的。如果要避免 NPE,请抛出自定义异常。但不要返回负数。如果调用者不检查返回值,你总会遇到问题。但是进行 false 计算(因为结果例如乘以 -1)肯定比未捕获的异常更难调试。

【讨论】:

  • 很好,确实存在调用者执行错误计算的危险。这就是为什么我认为文档如此重要的原因。正如我在回答中提到的,如果我已经记录了返回类型,我不妨将其设为 null
  • 在 Java 8 中(问这个问题时还有好几年的时间),您应该为此目的使用 Optional<Integer>。在此处对已接受的答案添加此评论,以防有人偶然发现此问题。
  • 其实OptionalInt.
【解决方案2】:

在查找未给出结果的情况下返回null 是表示不存在的正常方法。在这种情况下,我会选择它。 (标准 Java Map 类的查找方法是使用 null 的示例,以防映射不包含键。)

至于为 ID 返回一个特殊值,我只建议在您的系统已经包含表示特殊 ID 的特殊值时这样做。

另一个经常听到的可能性是在这种情况下抛出异常。但是使用异常来传递状态是不明智的,所以我也不会这样做。

【讨论】:

  • 关于你的最后一句话:为什么使用异常来传递状态是不明智的,在这种情况下会传递什么状态?
  • 在这种情况下,传递状态将是表中不存在名称。异常旨在表示通常不会发生的异常情况,而在正常执行期间传递状态 - 使用方法参数和返回值来传递状态。 (并且由抛出的异常展开的堆栈的性能低于返回值。)
【解决方案3】:

我认为在这种情况下返回 null 是合法的。只需确保正确记录意图即可。

在这种情况下返回负值是可以的,但这不是一个全面的解决方案。如果数据库中允许负值怎么办?

编辑:我想补充一下关于 SO 关于返回 null 或空列表(或数组)的相关讨论。我赞成返回空列表或数组而不是 null,但是 context 是不同的。当试图获取一个列表时,它通常是父对象的一部分,并且父对象有一个空列表而不是空引用实际上是有意义的。在这种情况下,null 是有意义的(= 未找到),没有理由避免返回它。

【讨论】:

    【解决方案4】:

    我希望这对你来说不是一个真正的方法。您没有在方法范围内关闭 Statement 或 ResultSet。

    【讨论】:

    • 好点,虽然这并不是问题的真正答案。
    • 正确,但有时坚持这个问题并不是最好的策略。其他人给出了完全可以接受的符合法律规定的答案。为什么只是重复呢?
    • 我认为@TM 的意思是暗示您应该发表评论而不是答案。
    • @harschware - 是的,我知道重点是什么。我碰巧不同意。我所说的完全正确和恰当,我是否将其放在答案或评论中似乎与我无关。为什么重要?
    • @duffymo - 因为如果你在与问题没有任何关系的情况下输入答案,那么你只是在寻找代表。 meta.stackexchange.com/questions/17447/…
    【解决方案5】:
    • 不要使用错误代码!哪个值是错误?它永远不会成为合法的返回值吗?什么都没赢。

    • Null 不好。大多数调用者代码必须对结果进行 if not null 检查。有时选择可能会返回 null。是否应该与没有行不同的处理?

    • 抛出类似 NoSuchElementException 的异常,而不是返回 null。这是一个未经检查的异常,调用者可以处理它或传递它。而如果调用者想要处理,try catch 并不比 if not null 复杂。

    【讨论】:

      【解决方案6】:

      我建议你考虑一下选项模式。

      选项模式充当您返回类型的包装器,并定义了两种特殊情况:option.none() 和 option.some()。这样,您始终知道返回的类型(选项),并且可以使用 option.isSome() 和 option.isNone() 等方法检查返回的 Option 对象中是否有值。

      这样,您可以保证没有任何未经检查的空值。

      当然,所有这些都是以增加代码复杂性为代价的。

      有关选项类型的更多信息,请参阅here(Scala 代码,但主体相同)

      【讨论】:

        【解决方案7】:

        不,不会。如果您事后对其进行操作,它只会抛出 NPE,就好像它是一个原语而不检查它一样。例如。 i++ 等等。您的示例是有效的(期望 JDBC 代码本身正在泄漏资源)。如果您不需要实际的id,那么您也可以只返回一个boolean

        【讨论】:

          【解决方案8】:

          这可能会给新手用户带来很大的麻烦。优秀的编码人员会认识到,如果名称无效,则可能会返回 null。说了这么多,更标准的还是扔一些exception

          【讨论】:

            【解决方案9】:

            结合自动装箱可能会很棘手。 如果我这样做:

            final int tid = tidForTerm("term");
            

            并且“term”不存在,我会得到一个 NPE,因为 Java 试图将 Integer (null) 拆箱为原始 int。

            尽管如此,在某些情况下,对整数使用 null 实际上是件好事。在具有可选 int 值的实体中,例如一个城市的人口。在这种情况下,null 意味着没有可用的信息。

            【讨论】:

              【解决方案10】:

              一个有趣的问题和大量可能的解决方案:

              1. 创建一个 HasArgument 方法并要求用户调用它,问题这可能会很慢并且重复工作
              2. 如果某个值不在数据库中,则抛出异常,仅应在意外情况下使用
              3. 使用附加值表示无效的返回值,null 和负值可以为您工作,但如果不检查它们可能会导致代码稍后出现问题。
              4. 返回带有 isValid() 和 getValue() 方法的包装器,其中 getValue() 无效时会引发异常。这将解决 1 和 3 的问题,但可能有点过于含糊。

              【讨论】:

                【解决方案11】:

                我想说最好的解决方案取决于您的方法的名称,您应该考虑您的方法的名称,以及它们是否应该返回 null 或抛出异常。

                tidOfTerm 向我暗示 Term 应该存在,所以发现不存在应该抛出异常。

                如果术语名称在您自己的代码的控制之下,并且找不到它表明您的代码或环境中存在错误,那么您可能需要抛出 IllegalArgumentException。

                如果术语名称参数不受您的控制,并且找不到有效术语是一种完全有效的情况,那么我会将您的方法重命名为 findTidForTermName 之类的名称,以暗示正在进行某种搜索执行,因此搜索可能找不到任何东西。

                【讨论】:

                  【解决方案12】:

                  我同意海报。 Integer 是一个包装器,因此应该用于计算、转换等(我认为您打算这样做)。不要返回空值,使用负数......它更优雅一些,并且允许您进行更多控制。恕我直言。

                  【讨论】:

                  • 如果忘记检查负数,就会冒着用负数进行计算、转换等的风险。如果确实检查负数,也可以检查 null。
                  【解决方案13】:

                  请不要编写返回 null 的代码。这意味着对您的代码的每次调用必须检查 null 以保持稳健。每次。总是。

                  考虑返回一个列表,而不是包含可能为零的返回值。

                  【讨论】:

                  • 当返回类型为 Integer 时,“返回列表”如何相关?
                  • 返回 null 是完全有效的,并且在无数 API 中非常常见。只要您记录下来,这绝对是正确的做法。
                  • @Skaffman。无数的 NPE 发生在程序员没有检查来自此类 API 的返回值与 null 的情况。此外,当您在一行中有一个 `a().b().c()' 构造时,您无法立即判断哪个调用产生了 NullPointerException。我认为 Jetbrains 在他们的 @NotNull 注释中是绝对正确的。 jetbrains.com/idea/documentation/howto.html
                  • @duffymo,在这种特殊情况下,您不能这样做,因此需要进行更改。您是否同意或不同意对 null 返回值的态度?
                  • 在这种特殊情况下,该方法似乎返回了一个 id,一个主键。这就是 Hibernate 将实例标记为未保存的方式:onjava.com/pub/a/onjava/2006/09/13/…。休眠完全错了吗?我不这么认为。
                  【解决方案14】:

                  是的,它应该导致 NPE,是的,您应该在调用方法(或其他合适的地方)中捕获它。您的方法返回 NULL 的最可能原因是当没有记录时,正确的处理方法是抛出异常。告诉某人你没有他要求的东西的完美例外是 NPE。

                  返回错误代码(例如 -1)不好,因为:

                  a) 如果您要处理许多错误(例如,无法读取 DB、可以读取 DB 但 DB 中不存在对象、找到对象但某些内容已损坏等),则返回错误代码不会区分错误的类型。

                  b) 将来如果 -1 成为合法术语 id,那么将很难更改它(如果您必须使用 -1,那么(编辑:在 C 中)至少执行 #define ERRORCODE -1 并使用ERRORCODE 无处不在)

                  【讨论】:

                  • 您真的只是建议在 Java 问题中使用#define 吗? (我几乎-1)
                  • 不告诉你扔一个 NPE。但是您应该愉快地返回 null 并在调用函数中处理它。如果在它为空时在调用函数中访问它,则应该捕获 NPE 并从那里开始工作。认为我在原帖中没有说清楚,但你明白我的意思。
                  猜你喜欢
                  • 2011-10-12
                  • 1970-01-01
                  • 2012-08-30
                  • 2011-01-16
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-04-05
                  • 1970-01-01
                  相关资源
                  最近更新 更多