Web服务返回一个巨大的XML,我需要访问它的深层嵌套字段。例如:
return wsObject.getFoo().getBar().getBaz().getInt()
问题是getFoo(),getBar(),getBaz()可能所有的回报null。
getFoo()
getBar()
getBaz()
null
但是,如果我null在所有情况下都进行检查,则代码将变得非常冗长且难以阅读。此外,我可能会错过某些领域的检查。
if (wsObject.getFoo() == null) return -1; if (wsObject.getFoo().getBar() == null) return -1; // maybe also do something with wsObject.getFoo().getBar() if (wsObject.getFoo().getBar().getBaz() == null) return -1; return wsObject.getFoo().getBar().getBaz().getInt();
可以写吗
try { return wsObject.getFoo().getBar().getBaz().getInt(); } catch (NullPointerException ignored) { return -1; }
或将其视为反模式?
捕获NullPointerException是一件非常有问题的事情,因为它们几乎可以在任何地方发生。从错误中获取一个错误,意外地捕获它,然后像一切正常一样继续进行非常容易,从而隐藏了一个真正的问题。处理起来非常棘手,因此最好完全避免。(例如,考虑对null进行自动拆箱Integer。)
NullPointerException
Integer
我建议你改用Optional该类。当你要使用存在或不存在的值时,这通常是最好的方法。
Optional
使用它,你可以这样编写代码:
public Optional<Integer> m(Ws wsObject) { return Optional.ofNullable(wsObject.getFoo()) // Here you get Optional.empty() if the Foo is null .map(f -> f.getBar()) // Here you transform the optional or get empty if the Bar is null .map(b -> b.getBaz()) .map(b -> b.getInt()); // Add this if you want to return an -1 int instead of an empty optional if any is null // .orElse(-1); // Or this if you want to throw an exception instead // .orElseThrow(SomeApplicationException::new); }
为什么可选? 使用Optionals代替null可能不存在的值使事实对于读者来说非常明显和清楚,并且类型系统将确保你不会意外忘记它。
Optionals
你还可以访问更方便地使用这些值的方法,例如map和orElse。
map
orElse
缺席有效还是错误? 但是还要考虑中间方法返回null是否是有效结果,或者这是错误的征兆。如果始终是错误,则抛出异常可能比返回特殊值或使中间方法本身抛出异常更好。
也许还有更多可选件? 另一方面,如果中间方法中缺少的值仍然有效,也许你也可以将Optional它们切换为s?
然后,你可以像这样使用它们:
public Optional<Integer> mo(Ws wsObject) { return wsObject.getFoo() .flatMap(f -> f.getBar()) .flatMap(b -> b.getBaz()) .flatMap(b -> b.getInt()); }
为什么不选? 我能想到的不使用的唯一原因Optional是,这是否在代码的性能关键部分,以及垃圾回收的开销是否是一个问题。这是因为Optional每次执行代码时都会分配一些对象,而VM 可能无法对其进行优化。在这种情况下,你的原始if测试可能会更好。