4

所以这是关于我最近被问到的一个面试问题。面试官首先问我我们是如何创建自定义异常的。在回答这个问题时,他问我如何创建一个 RunTimeExceptions。我说过我们会以与创建已检查异常相同的方式创建它们。只是我们的自定义异常将从 RunTimeException 类扩展。然后他问你会在什么场景下创建自己的 RunTimeException。现在我想不出一个好的答案。在我的任何项目中,我们都没有创建自定义 RunTimeExceptions。

我也认为我们永远不应该创建 RunTimeExceptions。JVM 只能以有限的方式失败,它可以很好地处理它们。在编写应用程序时,我们无法预测会发生哪些运行时异常,因此我们不需要处理它们。如果我们可以预测这些条件,那么它们就不是 RunTimeExceptions。既然我们既不需要新的运行时异常,也不需要处理运行时异常,为什么我们需要创建一个自定义的 RunTimeException。我们可以预先认为可能的失败条件的所有事情都应该在编译时处理,这将是一个检查异常。对?只有在编译时无法处理的事情和依赖运行时的事情才会进入 RunTimeExceptions 的类别。

即使我们编写了自定义 RunTimeExceptions,然后编写了一个应该抛出该 RunTimeException 的自定义方法 - 我们如何确保该方法将抛出该特定 RunTimeException。我们如何进行映射。这对我来说似乎不可能。

我在这里错过了什么/很多东西吗?友善的建议。

谢谢,陈。

4

4 回答 4

6

我认为面试官是想看看你是否理解运行时异常的目的,即表示程序员的错误(与应用程序异常相反,它表示执行环境存在问题)。

RuntimeException每当您的方法需要发出相当于编程错误的条件信号时,您都可以并且应该创建子类,并且您需要提供有关异常描述的错误的其他信息。

例如,考虑一个允许您将数据存储在稀疏多维数组中的类。此类类可能提供的 API 之一是获取索引数组的 getter。索引的数量需要等于数组中的维数,并且每个索引必须在其范围内。提供一个包含不正确数量的元素或一个或多个元素超出其边界的数组参数是编程错误。您需要使用运行时异常发出信号。如果你想发出这个错误的信号,并提供一个完整的错误说明,你的子类IllegalArgumentException,一个子类RuntimeException,来构建你自己的异常。

最后,当您想要子类化时还有另一种情况RuntimeException:当您应该提供“常规”异常时,但您不希望您的用户将 API 的每个调用包装在try/catch块中。在这种情况下,您可以替换单个方法

void performOperation() throws CustomApplicationException;

用一对方法

boolean canPerformOperation();
void performOperation();

第一个方法告诉调用者在当前状态下调用第二个方法是安全的;它从不抛出异常。

第二种方法仅在第一种方法返回时的状态下false失败,使失败成为编程错误,从而证明使用RuntimeException来表示此类失败是合理的。

于 2013-07-31T09:53:05.493 回答
4

Checked Exception vs Unchecked Exception 是 Java 开发人员之间的长期争论。我不是来生火的,只是想和大家分享一下我在工作中是如何使用它的。

例如,另一个服务调用我的服务器以获取客户信息。输入是customerID,我会返回一个customer对象

// Web Service interface
public CustomerInfo getCustomerInformation(int customerId, int securityToken) {
   check(securityToken);
   Customer customer = merchantService.getCustomer(customerId);
   return customer.getInfo();
}

// MerchantService
public Customer getCustomer(int customerId) {
   return customerService.getCustomer(customerId);
}

如果系统找不到特定客户会发生什么?当然它会抛出异常或返回null。但是返回 null 是不好的,因为它会让你每次从服务调用时都检查 null。所以我抛出异常:

// Customer service
public Customer getCustomer(id) {
   Customer customer = getCustomerFromDB();
   if (customer == null) throw CustomerNotExistedException();
   return customer;
}

现在的问题是 CustomerNotExistedException 是 Exception 还是 RuntimeException。如果是已检查异常,则需要在调用getCustomer. 这意味着您必须在 MerchantService 中找到它。但是,您想要的只是在 WebService 级别产生 404 错误,因此在 MerchantService 捕获它只会再次抛出异常。它污染了代码。

在一般情况下,我经常使用 RuntimeException 让一些异常“冒泡”到可以处理它们的级别。

作为参考,我推荐Robert C. Martin 的 Clean code一书。它很好地解释了我们应该如何使用异常来处理 Java 中的错误。

于 2013-07-31T10:16:35.263 回答
1

如果出现以下情况,您将创建自己的RuntimeException子类:

  • 您不希望它是一个已检查的异常,因为您不希望调用者显式地捕获该异常。(我个人认为检查异常在标准库中被过度使用了。)
  • 您仍然希望提供更多信息,而不仅仅是一条消息(只是类型本身是日志中一个有用的起点)。

HibernateException是 Hibernate ORM 中的一个示例。

于 2013-07-31T09:50:07.973 回答
0

我认为当您创建自定义异常时,请不要子类RuntimeException化,这违背了创建自定义异常的全部目的。

即使我们编写了自定义 RunTimeExceptions,然后编写了一个应该抛出该 RunTimeException 的自定义方法 - 我们如何确保该方法将抛出该特定 RunTimeException。

这里的要点实际上是方法的调用者不需要将它包围在一个try-catch块中,因为它不是一个检查异常。除非您有充分的理由抛出自定义的未经检查的异常,例如,只是为了为日志记录等提供额外的自定义信息,否则不要这样做。另一个糟糕的实现是有时您只想在代码中捕获已检查的异常并抛出自定义的未检查异常以摆脱调用者代码中的所有 try-catch。

于 2013-07-31T09:48:45.270 回答