【问题标题】:Better null-management try-catch with Java 8使用 Java 8 更好的空管理 try-catch
【发布时间】:2017-06-06 12:27:34
【问题描述】:

给定以下代码:

StaticPOIDataType response = null;
try {
  final JAXBContext jc = JAXBContext.newInstance(ObjectFactory.class);
  final Unmarshaller unmarshaller = jc.createUnmarshaller();
  unmarshaller.setSchema(getSchema());

  response =((JAXBElement<StaticPOIDataType>) unmarshaller.unmarshal(cpoGatewayURL)).getValue();

} catch (JAXBException e) {
  e.printStackTrace();
} finally {
  return response;
}

我听说有一个新的 Java 8 功能可以通过避免空初始化以更优雅的方式表达这一点。但我不知道要搜索什么。

【问题讨论】:

标签: java


【解决方案1】:

您的代码的作用是:

  • 调用一些方法
  • 如果它抛出异常,记录(或其他)错误并返回 null
  • 否则返回它返回的内容

做到这一点的最干净的方法——这不是新的——是:

try {
    return someMethod(...);
} catch (SomeException e) {
    logOrWhatever(e);
    return null;
}

有些人反对多个returns——但在这样的短块中,这是最清晰的方法(如果你的块不是这么短,请进行 extract-method 重构直到它是)。

只有一个return 的替代方案更长更混乱,并且涉及在比必要的更广泛的范围内声明一个可变变量:

Foo response = null;
try {
   response = someMethod(...);
} catch (SomeException e) {
   logOrWhatever(e);
}
return response;
  • 它更杂乱。想想你需要读多少资料才能回答“如果someMethod() 抛出异常,这个方法会返回什么?”这个问题。在第一个示例中,它就在catch 块中。在第二个中,您必须通过所有可能的状态更改来跟踪代码到response
  • response 不能声明 final -- 我认为你不应该在任何地方都使用 final,但我确实认为拥有尽可能多的变量是件好事 可以被宣布为最终的。
  • response 的范围在try 块之外。整洁的方法将数据保持在更窄的范围内,这总是好的。

通过将return 放入finally 块中,您的代码会执行其他操作——如果任何其他类型的异常 被抛出,null 将在没有任何日志记录或其他的情况下返回异常处理。这不太可能是一个好主意——它只会让错误难以诊断:Try-catch-finally-return clarification


但是,更一般地说,您应该尽量避免返回 null。您的问题标题提到了“null-management”,但是是您在程序中引入了 null。如果你没有选择返回 null,你就不必处理它的问题:

  • 如果 null 表示“出现问题”,请不要这样做。向上处理异常(如果您愿意,可以将其重新抛出为不同的异常类型)
  • 如果方法的语义是“这可能会返回响应,或者可能没有响应”,请考虑:
    • 让方法返回 Optional&lt;Response&gt; -- 现在方法签名是诚实的
    • 使用“空对象”模式。也就是说,不是返回null而是返回new EmptyResponse()

这样你的代码可以更加简单和干净,因为它不必充满 if(x==null) 守卫。

【讨论】:

  • @AxelH Map 是 19 年前设计的。我们继续使用它,因为它就在那里。但我们不应该重蹈覆辙。如果今天设计它可能会返回Optional&lt;T&gt;
  • 好吧 Optional 是相反的 ;) 直到最近,在办公室,我们仍在运行 Java 6... ;-) 结束一些建设性的事情,这个 post 很好论证什么是 null 的有效/无效用法。我只是不同意那些说“永远不要使用 NULL”的人;)
  • @AlexH Java 6 已经 11 岁了。但是很容易滚动你自己的Optional,或者使用空对象模式,或者使用像 Guava 这样的库(尽管它是一个古老的版本)
  • @AlexH 很好,但问题不包括任何关于受历史决策限制的内容。
  • 我从来没有说过这是个问题...你是那个一直在争论的人,所以它稍微改变了话题..来吧,它 axelh :(
【解决方案2】:

您正在寻找的是可选的。这是下面的代码享受

try {
        final JAXBContext jc = JAXBContext.newInstance(ObjectFactory.class);
        final Unmarshaller unmarshaller = jc.createUnmarshaller();
        unmarshaller.setSchema(getSchema());

        return Optional.ofNullable((JAXBElement<StaticPOIDataType>) unmarshaller.unmarshal(cpoGatewayURL)).getValue());

    } catch (JAXBException e) {
        e.printStackTrace();
    }

    return Optional.empty();

【讨论】:

  • 可能是这样,但我个人更喜欢“null”版本,因为方法中只有一个 return 语句。
  • 有两个返回语句 return Optional.ofNullable((JAXBElement) unmarshaller.unmarshal(cpoGatewayURL)).getValue()); return Optional.empty();
  • 这是我的问题;)我知道这个逻辑,但我发现在一个方法中有多个“return”语句很麻烦。
  • 然后更改方法签名以抛出 JAXBException 异常,然后转换为您的应用程序异常并处理它。那么你将有一个回报
  • 我得到:原因:不存在类型变量 T 的实例,因此 Optional 符合 StaticPOIDataType
【解决方案3】:

我认为您正在寻找 Java 8 中的 Optional,

请查找包含精美示例的此文档。

https://dzone.com/articles/java-8-optional-avoid-null-and

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-25
    • 1970-01-01
    • 1970-01-01
    • 2012-05-27
    • 1970-01-01
    • 2023-03-03
    • 1970-01-01
    • 2018-06-24
    相关资源
    最近更新 更多