2013-03-04 85 views
67

我担心这是一个运行时异常,所以应该谨慎使用它。
标准使用案例:何时应抛出IllegalArgumentException?

void setPercentage(int pct) { 
    if(pct < 0 || pct > 100) { 
     throw new IllegalArgumentException("bad percent"); 
    } 
} 

但是,这似乎将迫使下面的设计:

public void computeScore() throws MyPackageException { 
     try { 
      setPercentage(userInputPercent); 
     } 
     catch(IllegalArgumentException exc){ 
      throw new MyPackageException(exc); 
     } 
} 

为了得到它重新成为一个检查异常。

好的,但让我们一起去。如果你输入错误,你会得到一个运行时错误。所以,首先这实际上是一个相当困难的政策来实现均匀的,因为你可以有做的很相反的转换:

public void scanEmail(String emailStr, InputStream mime) { 
    try { 
     EmailAddress parsedAddress = EmailUtil.parse(emailStr); 
    } 
    catch(ParseException exc){ 
     throw new IllegalArgumentException("bad email", exc); 
    } 
} 

更糟糕的是 - 当检查0 <= pct && pct <= 100客户端代码可望静态做的,事实并非如此以获取更高级的数据,例如电子邮件地址,或者更糟糕的是,必须对数据库进行检查,因此通常客户端代码无法预先验证。

所以基本上我所说的是我没有看到使用IllegalArgumentException的有意义的一致性政策。它似乎不应该被使用,我们应该坚持我们自己的检查异常。什么是好的用例来抛出这个?

回答

51

的API文档的IllegalArgumentException的:

抛出,表明一个方法传递了一个不合法或不正确的说法。

通过观察how it is used in the jdk libraries,我会说:

  • 这似乎是一种防御措施抱怨显然是错误的输入之前的输入可以进入作品,并导致一些中途失败通过一个无意义的错误消息。

  • 它用于那些抛出一个检查异常太烦人的情况(虽然它在java.lang.reflect代码中出现,在这种情况下,关于checked-exception-throwing的荒谬级别的关注并不明显)。

我会用抛出:IllegalArgumentException做最后一搏的防守参数,检查常用工具(尽量保持与JDK用法一致),其中期望是一个不好的说法是一个程序员的错误,类似于NPE。我不会用它来实现业务代码中的验证。我当然不会将它用于电子邮件示例。

+5

我认为这个建议“期望是一个糟糕的论点是一个程序员错误”与我所见过的使用方式最为一致,所以接受了这个答案。 – djechlin 2013-03-07 03:22:27

9

“谨慎地”抛出运行时异常并不是一个很好的策略 - 有效的Java建议您在合理预期调用者可以使用时检查异常。 (程序员错误是一个具体的例子:如果一个特定的案例表明程序员错误,那么你应该抛出一个未经检查的异常;你希望程序员有一个逻辑问题发生的地方的堆栈跟踪,而不是试图自己处理它。)

如果没有恢复的希望,那么可以随意使用未经检查的异常;捕捉它们没有意义,所以这非常好。

虽然这不是100%从你的例子中清楚的例子,但是这个例子在你的代码中。

+0

我认为“合理的预期恢复”是杞人忧天。任何操作'foo(data)'都可能作为'for data(list data)foo(data)'的一部分发生;'即使某些数据格式错误,调用者可能希望尽可能多地成功。如果我的应用程序失败意味着交易不会经历那可能更好,如果这意味着核冷却脱机是不好的,那么也包括程序错误。 – djechlin 2013-03-04 19:24:57

+0

'StackOverflowError'和这样的情况下,调用者无法合理预期从中恢复。但它听起来像应该检查任何数据或应用程序逻辑级别的情况。这意味着你的空指针检查! – djechlin 2013-03-04 19:25:54

+3

在核冷却应用中,我宁愿在测试中失败,也不愿让程序员认为不可能不被忽视的情况。 – 2013-03-04 20:09:00

4

在Oracle官方指定教程,它指出:

如果客户可以合理预期从异常恢复, 使它成为一个检查异常。如果客户端无法执行任何操作以从异常中恢复 ,请将其设置为未检查的异常。

如果我有使用JDBC数据库的应用程序进行交互,而我有需要的参数作为int itemdouble price的方法。相应项目的price从数据库表中读取。我只需将购买的item总数与price值相乘并返回结果。尽管我总是在我的最后(申请结束)确定表格中的价格字段值永远不会为负数。但是如果价格值出来怎么办?否定?它表明数据库方面存在严重问题。也许是运营商输入错误的价格。这是调用该方法的应用程序的其他部分无法预料并且无法从中恢复的问题。它在您的数据库中是一个BUG。所以,IllegalArguementException()应该抛出在这种情况下,将声明the price can't be negative
我希望我已经表达了我的观点清楚..

17

当谈到“糟糕的输入”时,你应该考虑输入来自哪里。

如果用户或其他外部系统输入的输入是不受控制的,那么您应该预期输入无效,并始终对其进行验证。在这种情况下抛出一个检查的异常是完全可以的。您的应用程序应通过向用户提供错误消息来从此异常中“恢复”。

如果输入来自您自己的系统,例如你的数据库或应用程序的其他部分,你应该可以依赖它来证明它是有效的(它应该在它到达之前进行验证)。在这种情况下,最好抛出一个未经检查的异常,如IllegalArgumentException,这个异常不应该被捕获(通常你​​不应该捕获未经检查的异常)。这是一个程序员的错误,无效的值首先到达那里;)您需要修复它。

+1

为什么“你永远不应该捕捉不受限制的例外”? – 2015-12-14 17:19:37

+5

因为一个未经检查的异常是由于编程错误而引发的。抛出这种异常的方法的调用者不能合理地期望从其中恢复,因此通常无法捕捉到它们。 – Tom 2015-12-15 20:53:53

+0

'因为一个未经检查的异常是由于编程错误而被抛出的'帮助我清除了很多东西在我脑海中,谢谢:) – svarog 2017-06-27 12:25:50

5

任何API应该检查任何公开的方法的每一个参数的有效性执行前:

void setPercentage(int pct, AnObject object) { 
    if(pct < 0 || pct > 100) { 
     throw new IllegalArgumentException("pct has an invalid value"); 
    } 
    if (object == null) { 
     throw new IllegalArgumentException("object is null"); 
    } 
} 

他们是时代错误的99.9%,在应用,因为它是要求不可能的操作,以便在最终它们是应该使应用程序崩溃的错误(所以它是不可恢复的错误)。

在这种情况下,在快速失败的方法之后,应该让应用程序完成以避免损坏应用程序状态。

+0

相反,如果一个API客户端给我一个不好的输入,我应该*不*会崩溃我的整个API服务器。 – djechlin 2017-09-29 15:52:22

+0

当然,它不应该崩溃你的API服务器,但返回一个异常给调用者这应该不会崩溃任何东西,但客户端。 – 2017-10-02 07:27:57

+0

你在评论中写的不是你在答案中写的。 – djechlin 2017-10-02 14:14:54

相关问题