使用多个吸气剂时尝试捕获而不是空检查

时间:2016-08-19 11:19:47

标签: java

我的问题如下,我有一个很长的Getter,即,

objectA.getObjectB().getObjectC().getObjectD().getObjectE().getName();

由于"坏"数据库/实体设计(有些事情比其他人晚一些介绍)getObjectB()getObjectC()getObjectD()可能会返回NULL

通常我们会一直使用空值检查,但在这种情况下,我必须使用

ObjectB b = objectA.getObjectB();
if (b != null) {
    ObjectC c = b.getObjectC();
    if (c != null) {
        ObjectD d = c.getObjectD();
        if (d != null)
           return d.getObjectE().getName();
    }
}
return "";

相反,简单地使用try-catch块

会容易得多
try {
   return objectA.getObjectB().getObjectC().getObjectD().getObjectE().getName();
} catch (NullPointerException e) {
   return "";
}

在这种情况下,我并不关心哪个对象返回NULL,它要么显示名称要么不要显示。是否有任何并发​​症或使用try-catch而不是检查是不好的设计?

感谢您的意见。

3 个答案:

答案 0 :(得分:7)

如果是使用Java 8的选项,您可以使用Optional,如下所示:

Optional.ofNullable(objectA)
    .map(a -> a.getObjectB())
    .map(b -> b.getObjectC())
    .map(c -> c.getObjectD())
    .map(d -> d.getObjectE())
    .map(e -> e.getName())
    .orElse("");

答案 1 :(得分:4)

这种方法链被称为"火车残骸"并不是首选。 这样的陈述也违反了Law of Demeter。让我举一个 Robert C Martin 清洁代码一书的例子:

String scratchDirPath = ctxt.getOptions().getScratchDir().getAbsolutePath();
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(scratchDirPath));
//write to file...

这与你所拥有的类似,这是一种不好的做法。这至少可以重构到下面:

Options options = ctxt.getOptions();
File scratchDir = options.getScratchDir();
String scratchDirPath = scratchDir.getAbsolutePath();
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(scratchDirPath));
//write to file...

这仍违反了得墨忒耳法,但至少部分更好。 最好的方法是找出为什么需要scratchDirPath并请求ctxt对象提供给你。所以它看起来像 -

BufferedOutputStream bos = ctxt.createScratchDirFileStream();

这样ctxt不会暴露其所有内部。这将调用代码与ctxt的实现分离。

答案 2 :(得分:0)

这只是你和你的团队可以做出的判断,但是(至少)我会调出一个客观的事情:在其中一个方法返回null的情况下,你的第一个代码块比第二个表现更好。相对于简单的分支,抛出异常是昂贵的。 (在没有方法返回null的情况下,我认为第二个可能比第二个快得多,因为你避免了分支。)在任何一种情况下,如果性能很重要,在您的环境中测试它。 (但test it properly;微观基准很难。使用工具。)

大多数时候,差异在现实世界中并不重要,当然,这是运行时的重大差异。