【问题标题】:Gracefully avoiding NullPointerException in Java在 Java 中优雅地避免 NullPointerException
【发布时间】:2010-11-01 03:01:21
【问题描述】:

考虑这一行:

if (object.getAttribute("someAttr").equals("true")) { // ....

显然这一行是一个潜在的错误,属性可能是null,我们会得到一个NullPointerException。所以我们需要将其重构为两种选择之一:

第一个选项:

if ("true".equals(object.getAttribute("someAttr"))) { // ....

第二个选项:

String attr = object.getAttribute("someAttr");
if (attr != null) {
    if (attr.equals("true")) { // ....

第一个选项难读但更简洁,而第二个选项意图清晰但冗长。

就可读性而言,您更喜欢哪个选项?

【问题讨论】:

    标签: java coding-style nullpointerexception code-readability


    【解决方案1】:

    我一直在用

    if ("true".equals(object.getAttribute("someAttr"))) { // ....
    

    因为虽然它读起来有点困难,但它不那么冗长,而且我认为它足够可读,所以你很容易习惯它

    【讨论】:

      【解决方案2】:

      我喜欢选项 1,我认为它足够可读。

      选项 3 顺便说一句,将引入一个 getAttribute 方法,该方法将默认值作为参数。

      【讨论】:

      • 这个问题是关于 'if' 块的,所以关于你的选项 3:“你不能总是相信该方法永远不会返回空值
      • 当然你可以确保它永远不会返回 null 作为默认值。
      • 选项 3 就是将错误处理和空检查移到一个根据 DRY 的方法中。
      • 我同意,但我的意思是您并不总是测试您编写的方法,因此您不能依赖返回值不会为空
      【解决方案3】:

      Util.isEmpty(string) - 返回string == null || string.trim().isEmpty() Util.notNull(string) 如果string == null 返回 "",否则返回字符串。 Util.isNotEmpty(string) 回归! Util.isEmpty(string)

      我们有一个约定,对于字符串,Util.isEmpty(string) 在语义上表示真,Util.isNotEmpty(string) 在语义上表示假。

      【讨论】:

        【解决方案4】:

        在第二个选项中,您可以利用短路&&

        String attr = object.getAttribute("someAttr");
        if (attr != null && attr.equals("true")) { // ....
        

        【讨论】:

        • 确实可以,但它是有利于可读性的优化,总是一个坏主意。
        • 嗯,支持优化?相反,我认为这比选项 1 更具可读性。
        • 是的 - 风格问题没有明确的答案。这是你习惯的。我个人已经习惯了这种风格,因为它也适用于从 C/C++ 派生的许多其他语言。如果您的组织/项目有代码约定,请遵循其建议。
        • 这不是“优化”,也不是可读性差。我认为拥有两个 if 子句实际上的可读性要低得多,因为您最终得到的嵌套块比实际需要的要多。双 if 还为臭名昭著的“2ifs1else”错误打开了一个窗口:“if (a) if (b) print("a and b"); else print("not a and b");
        【解决方案5】:

        考虑到两者在功能上是等效的,总是渴望更短的代码。尤其是在这种不牺牲可读性的情况下。

        【讨论】:

          【解决方案6】:

          在某些情况下,简洁的方法开始时感觉不对,但实际上变得惯用了。这是其中之一;另一个是这样的:

          String line;
          while ((line = bufferedReader.readLine()) != null) {
            // Use line
          }
          

          病情的副作用?不可思议!除了当您识别特定模式时,它基本上比替代品更好。

          这种模式很相似——它在 Java 中很常见,我希望任何有经验的开发人员都能认出它。结果非常简洁。 (有趣的是,我有时会看到 C# 代码不必要地使用相同的习语 - 等式运算符适用于 C# 中的字符串。)

          底线:使用第一个版本,并熟悉它。

          【讨论】:

            【解决方案7】:

            这是一个很好的问题。 我通常使用不优雅:

            if (object.getAttribute("someAttr") != null && object.getAttribute("someAttr").equals("true")) { // ....
            

            (我不会再使用它了)

            【讨论】:

            • 不错!如果 getAttribute() 实际上有副作用怎么办?有时你运行一次,有时你运行两次。
            • 我可能会在我在这里看到的“常见编程错误”问题中写这个
            • 感谢 cmets。我知道这不好,我是来学习这样的东西的。还有一个问题:如果 getAttribute() 只是一种标准的 getter 方法,那么这种方法有什么问题 - 因此没有副作用?
            • +1 我认为有些人不阅读文本,只阅读代码。评论中的@question:以后可能会产生副作用。不太可能对吸气剂造成太严重的损坏,但有可能。可能会导致性能损失,例如,如果它在下一个版本中返回计算数据 - 特别是如果此代码无处不在。
            • 谢谢soulmerge,我明白了这个问题。我认为 stackoverflow 非常适合这样的事情。
            【解决方案8】:

            我还有一个答案;

            List<Map<String, Object>> group = jjDatabase.separateRow(db.Select("SELECT * FROM access_user_group  WHERE user_id=1 ;"));
            

            我的数据库中的“access_user_group”中没有“group_c80”作为列,因此在 get(0).get("group_c80") 中符合空指针异常。但我通过下面的代码处理了它:

            for (int j = 1; j < 100; j++) {
                                String rulId="0";//defult value,to privent null pointer exeption in group_c
                                try {
                                    rulId = group.get(0).get("group_c" + j)).toString();
                                } catch (Exception ex) {
                                    ServerLog.Print( "Handeled error in database for " + "group_c" + (j < 10 ? "0" + j : j) +"This error handeled and mot efect in program");
                                    rulId = "0";
                                }}
            

            【讨论】:

              【解决方案9】:

              这是我的方法,虽然需要一个 PropertyUtil 类,但它只写一次:

              /**
               * Generic method to encapsulate type casting and preventing nullPointers.
               * 
               * @param <T>          The Type expected from the result value.
               * @param o            The object to cast.
               * @param typedDefault The default value, should be of Type T.
               * 
               * @return Type casted o, of default.
               */
              public static <T> T getOrDefault (Object o, T typedDefault) {
                  if (null == o) {
                      return typedDefault;
                  }
                  return (T) o;
              }
              

              客户端代码可以这样做:

              PropertyUtil.getOrDefault(obj.getAttribute("someAttr"), "").equals("true");
              

              或者,对于列表:

              PropertyUtil.getOrDefault(
                  genericObjectMap.get(MY_LIST_KEY), Collections.EMPTY_LIST
              ).contains(element);
              

              或者对于 List 的消费者,它会拒绝 Object:

              consumeOnlyList(
                  PropertyUtil.getOrDefault(
                      enericObjectMap.get(MY_LIST_KEY), Collections.EMPTY_LIST
                  )
              )
              

              默认可能是空对象模式 https://en.wikipedia.org/wiki/Null_Object_pattern 的 impl

              【讨论】:

                猜你喜欢
                • 2010-09-21
                • 2023-03-15
                • 1970-01-01
                • 2011-09-20
                • 2016-06-28
                • 2019-07-06
                相关资源
                最近更新 更多