【问题标题】:Efficient null check for a compound object in Java [duplicate]Java中复合对象的有效空检查[重复]
【发布时间】:2016-12-12 08:01:09
【问题描述】:

一个程序创建一个带有多个选项卡的 JDialog 面板。其中一个选项卡有几个表。 JTable 具有可调整的列宽。此选项卡是在不同条件下生成的。有时从状态tabnull,有时选项卡存在,但tablenull。有时用户还没有调整列的大小。

如果用户调整了列的大小,我正在寻找一种方法来保存 columnWidth 值。在这种情况下检查 null 似乎很笨重:

jpanel.tab.table.width

我能找到的最好方法是:

if( jpanel!=null && 
    jpanel.jtab!=null &&
    jpanel.jtab.jtable!=null && ...

有没有更好的方法来做这个空检查?


我看到了这个问题:
is there a Java equivalent to null coalescing operator (??) in C#?

它没有列出解决方案并且很旧(Java 6-7 时间)。我希望在以后的版本中添加此功能。

【问题讨论】:

  • 我的意思是,如果我的item 的毛刺深度为 6-10 级,则此检查看起来不正确。当你应该使用 for 循环时,感觉就像多次重复相同的代码
  • stackoverflow.com/questions/5223044/… stackoverflow.com/questions/2768054/… stackoverflow.com/questions/271526/avoiding-null-statements 等 tl;dr 要么保留它,要么修复你的逻辑,而不是实现(使用 Optional 等)
  • 您确定需要检查所有级别是否为空吗?如果 null 对于这些字段中的许多字段来说不是有效值,则无需检查,而是让它抛出 NRP 异常。
  • 我知道否则我无法说服你,但无论如何,我会坚持使用“笨重”的语法,直到 Java 提供语法糖来缩短它。作为“正常”空值检查的一部分来捕获异常以节省一些击键并不是一个好的权衡,因为它在运行时可能非常低效。它还会在 IDE 中造成非常烦人的调试体验,因为代码会在异常抛出时不断中断。而且使用反射也很糟糕,因为它效率不高,而且如果您重命名/重构字段,您的代码很容易中断。
  • @sstan 实际上,你现在说服了我。较早的答案说“你不能这样做”,而你的评论是“你可以,但这不安全并且是一种不好的做法 - 最好写一个长检查然后养成丢弃异常的习惯”。这应该是一个公认的答案...

标签: java if-statement null


【解决方案1】:

没有办法完全按照您的意愿行事。 但是,您可以将所有内容都放入 try 语句中:

try { 
    myItem = bundle.category.subcategory.item;
} 
catch(NullpointerException ignored) {}

请注意,这看起来很受黑客攻击,而且是相当糟糕的编码实践。就清晰度而言,您当前的解决方案可能是最好的方法。


编辑:我尝试发布另一个 Anwser,但按钮是灰色的,所以我把它放在这里:

感觉就像重复相同的代码很多次,当你应该使用 for 循环时

您确实可以使用for 循环,但这将涉及反射 和许多样板代码。想象一下这样的事情:

static boolean checkDeepNull(Object root, String... attributes) throws NoSuchFieldException, IllegalAccessException {
    Object currentAttribute = root;
    for(int attr = 0; currentAttribute != null && attr < attributes.length; attr++){
        Field nextField = currentAttribute.getClass().getField(attributes[attr]);
        Object nextAttribute = nextField.get(current);
        if(nextAttribute == null) return false;
        currentAttribute = nextAttribute;
    }
    return true;
}

使用方法:if(checkDeepNull(bundle, "category", "subcategory", "item"))

【讨论】:

  • 您的解决方案不符合问题要求
  • 不,OP,不要这样做。 :(
  • 这个解决方案出现得较早,我看不出有什么问题。无声的投票是讨厌的。
  • 我明白这一点,我们都感谢您的努力。否决票是关于我们希望未来的人们将其作为一种实践或将其视为答案,而不是关于您的努力或本身不好的答案。这里没有答案是一种很好的做法,因此没有人真正得到支持。
【解决方案2】:

你可以有一个接口来确定可空性:

public interface Nullability {
    public boolean hasNulls();
}

然后简单地让父母像这样调用任何孩子:

public boolean hasNulls() {
    return this.bundle == null || bundle.hasNulls();
}

//in bundle
public boolean hasNulls() {
    return this.category == null || category.hasNulls();
}

无论如何,如果您必须对所有内容进行空检查,如果您不提供迭代方法,您将需要编写大量样板代码。这才是你真正应该关注的。

就个人而言,我非常不同意公开这样的字段。这是在设计中导致更多麻烦和错误的一种非常简单的方法。

【讨论】:

  • 如果类别有 两个 字段、一个有效的非 null 子类别和一个 null foo,这个想法将如何运作?
  • 你会检查多个可空值的#hasNulls。同样,这不是一个理想的解决方案,只是对 OP 问题的回答。实际上,更需要改变设计
【解决方案3】:

简短的回答是

您能否重新设计捆绑包以使其始终完全构建?即,如果bundle != null,那么类别、子类别和项目总是存在?这也有助于解决并发问题。基本上,如果空值给您带来问题,请尽可能不要让这些字段为空。

另一个选项是Null Object Pattern。基本上,您有一个 Bundle 的“默认”实现,它始终返回 getCategory(),它始终返回 getSubcategory() 的值,但最终对 getItem() 的调用返回 null 或其他表示“无”的东西。这是一个很棒的模式,但需要一些工作。

我犹豫是否建议,但很少有任何项目为空,在某些时候,捕获 NPE 可能更快更清晰,但这种风格确实应该避免。你的设计很糟糕,这是一种明确的代码味道。尽可能避免它。

try {
  return foo.bar.bap.zaz.blah.blah;
}
catch (NullPointerException ignored) {
  return null;
}

【讨论】:

  • 如果应该避免,也许最好不要建议。
  • @sstan。在原始问题下看到您的评论并添加了有关空对象模式的部分。
猜你喜欢
  • 2021-01-04
  • 1970-01-01
  • 1970-01-01
  • 2020-02-03
  • 1970-01-01
  • 2014-08-06
  • 1970-01-01
  • 2020-10-05
  • 1970-01-01
相关资源
最近更新 更多