76

这是今天与同事讨论时提出的。

Java 的 JavadocsIllegalStateException声明它:

表示方法已在非法或不适当的时间被调用。换言之,Java 环境或 Java 应用程序未处于请求操作的适当状态。

Effective Java 说(第 60 条,第 248 页):

另一个常用的异常是 IllegalStateException。如果由于接收对象的状态而调用非法,这通常是抛出的异常。例如,如果调用者在正确初始化之前尝试使用某个对象,这将是抛出的异常。

这里似乎有点不一样。javadocs 的第二句话听起来像是异常可以描述有关 Java 执行状态的非常广泛的条件,但 Effective Java 中的描述使它听起来像是用于与对象状态相关的条件方法已被调用。

我在 JDK(例如集合Matcher)和 Guava 中看到的用法肯定属于 Effective Java 所谈论的类别(“此对象处于无法调用此方法的状态”)。这似乎也与IllegalStateException's兄弟相一致IllegalArgumentException

IllegalStateExceptionJDK 中是否存在与“Java 环境”或“Java 应用程序”相关的合法用途?或者是否有任何最佳实践指南提倡将其用于更广泛的执行状态?如果不是,那为什么 javadocs 会这样写呢?;)

4

6 回答 6

44

这是 JDK 中此异常的一个特别合法的用法(请参阅:URLConnection.setIfModifiedSince(long)在它的 300 多种其他用法中:

public void setIfModifiedSince(long ifmodifiedsince) {
    if (connected)
        throw new IllegalStateException("Already connected");
    ifModifiedSince = ifmodifiedsince;
}

我认为这个例子很清楚。如果对象处于特定状态(“已连接”),则不应调用某些操作。在这种情况下,当建立连接时,某些属性无法设置。

当您的类具有随时间变化的某些状态(状态机?),使某些方法变得不相关或不可能时,此异常特别有用。考虑一个Carstart(),stop()fuel()方法的类。虽然打电话start()两次,一个接一个,可能没有错,但给一辆启动的汽车加油肯定是个坏主意。即 - 汽车处于错误状态。

可以说好的 API 不应该允许我们调用处于错误状态的方法,以便在编译时而不是在运行时发现类似的问题。在此特定示例中,连接到 URL 应返回带有方法子集的不同对象,所有方法在连接后均有效。

于 2012-10-02T21:09:39.053 回答
5

这是JDK中的一个示例。有一个名为 java.lang.Shutdown 的包私有类。如果系统正在关闭并且您尝试添加新挂钩,则会引发 IllegalStateException。有人可能会争辩说这符合“javadoc”指南的标准——因为它是处于错误状态的 Java 环境。

class Shutdown {    
...

   /* Add a new shutdown hook.  Checks the shutdown state and the hook itself,
    * but does not do any security checks.
    */
    static void add(int slot, Runnable hook) {
        synchronized (lock) {
            if (state > RUNNING)
                throw new IllegalStateException("Shutdown in progress");

            if (hooks[slot] != null)
                throw new InternalError("Shutdown hook at slot " + slot + " already registered");

            hooks[slot] = hook;
        }
    }

然而,它也说明了“javadoc”指南和“Effective Java”指南之间确实没有区别。由于 Shutdown 的实现方式,JVM 的关闭状态存储在一个名为 state 的字段中。因此,它也符合关于何时使用 IllegalStateException 的“Effective Java”指南,因为“state”字段是接收对象状态的一部分。由于接收对象 (Shutdown) 处于错误状态,因此会引发 IllegalStateException。

在我看来,关于何时使用 IllegalStateException 的两种描述是一致的。Effective Java 描述更实用一些,仅此而已。对于我们大多数人来说,整个 Java 环境中最重要的部分就是我们现在正在编写的类,所以这也是作者所关注的。

于 2012-10-02T21:49:33.100 回答
2

我想如果你看到IllegalStateException我会说第二个更合适的用法。很多包中都使用了这个异常

  • java.net
  • java.nio
  • java.util
  • java.util.concurrrent 等

要指定一个示例,如果队列已满,ArrayBlockingQueue.add会抛出此异常。现在 full 是对象的状态,它在不适当或非法的时间被调用

我猜两者的意思相同,但措辞不同。

于 2012-10-02T21:13:42.033 回答
1

给定一个库,它应该在检测到由于用户代码引起的错误时抛出一个IllegalStateException或,而库应该在检测到由于库自己的实现引起的错误时抛出一个。IllegalArgumentExceptionAssertionError

例如,在库的测试中,您可能希望库IllegalStateException在方法调用的顺序错误时抛出一个错误。但是你永远不会期望图书馆会抛出一个AssertionError.

于 2016-04-02T07:54:55.930 回答
0

这里没有“差异”。Bloch 的措辞中没有任何内容排除它在 JLS 中所说的内容。Bloch 只是说如果你有情况 A,抛出这个异常。他并不是说这个异常是/应该在这种情况下被抛出。JLS 表示如果 A、B 或 C 抛出此异常。

于 2012-10-03T00:00:41.200 回答
0

我遇到了这个:

try {
    MessageDigest digest = MessageDigest.getInstance("SHA-1");
    ...
} catch (NoSuchAlgorithmException e) {
    throw new AssertionError(e);
}

我认为即使这属于“Java 环境”类别,我也无法将其IllegalStateException放在这里。AssertionException

于 2014-05-01T02:02:12.950 回答