自定义运行时异常

时间:2013-07-31 09:47:03

标签: java custom-exceptions

所以这是关于我最近被问到的面试问题。面试官通过询问我们如何创建自定义异常来开始这一点。在回答这个问题时,他问我如何创建RunTimeExceptions。我说我们创建它们的方式与创建选中的Exceptions相同。我们的自定义异常将从RunTimeException类扩展。然后他问你在什么情况下会创建自己的RunTimeException。现在我想不出一个好的答案。在我的所有项目中,我们都创建了自定义RunTimeExceptions。

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

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

我在这里遗漏了什么/很多东西?请建议。

谢谢, 陈。

4 个答案:

答案 0 :(得分:6)

我认为面试官试图了解你是否理解运行时异常的目的,即发出程序员错误的信号(而不是应用程序异常,它表示执行环境存在问题)。

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

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

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

try

使用一对方法

catch

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

第二种方法仅在第一种方法返回void performOperation() throws CustomApplicationException; 的状态下失败,使失败成为编程错误,从而证明使用boolean canPerformOperation(); void performOperation(); 来表示此类失败。

答案 1 :(得分:4)

Checked Exception vs Unchecked Exception是Java开发人员长期以来的争论。我不会在这里点火,但只想和你分享我在工作中如何使用它。

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

// 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让一些异常“冒泡”到可以处理它们的级别。

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

答案 2 :(得分:1)

如果符合以下条件,您将创建自己的RuntimeException子类

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

HibernateException就是Hibernate ORM中的一个例子。

答案 3 :(得分:0)

我认为在创建自定义异常时,请不要继承RuntimeException,否则会破坏创建自定义异常的全部目的。

  

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

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