IllegalStateException的预期用途是什么?


76

今天在与同事的讨论中提出了这一点。

Javadocs for JavaIllegalStateException指出:

表示已在非法或不适当的时间调用了方法。换句话说,对于所请求的操作,Java环境或Java应用程序没有处于适当的状态。

而有效的Java说(第248页的第60项):

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

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

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

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


4
关于一个可能不相关的注释,我注意到StackOverflow的[illegalstatexception]标签说In Java, an exception that occurs when using multiple threads, whereby one thread modifies an object in a way that makes it incompatible with the use of that object in the second thread, thus putting the object into an illegal state.。??这是哪里来的?
安德鲁·麦克纳姆

3
“ Java应用程序”是您编写的应用程序,您可以在其中使用IllegalStateException(例如,直接使用或因为使用Guava而已)。差异在哪里?
Frank Pavageau

4
标签Wiki看起来是伪造的,我通过从这个问题中自由借用来提交了一个编辑;一旦新版本通过同行评审,您应该会看到它。
meriton

Answers:


43

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

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

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

当您的类具有随时间变化的某些状态(状态机?),从而使某些方法无关或不可能时,此异常特别有用。想想一Car类具有start()stop()fuel()方法。虽然一遍start()又一遍打两次电话,这可能没错,但是给启动的汽车加油肯定不是一个好主意。即-汽车处于错误状态。

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


1
我同意你的回答。但是,这并不能解释为什么Effectiva Java和番石榴使用这个异常就像一个IllegalArgumentException
查拉图斯特拉

4

这是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”指南和“有效Java”指南之间确实没有区别。由于实施Shutdown的方式,JVM的关闭状态存储在一个名为state的字段中。因此,它也符合何时使用IllegalStateException的“有效Java”指南,因为“状态”字段是接收对象状态的一部分。由于接收对象(Shutdown)处于错误状态,因此它将引发IllegalStateException。

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


1
啊,我喜欢这个例子!在InternalError刚刚ISE下面扔也证明它是多么有用做一个“你搞砸了”与“我搞砸了”的区别。而且,它确实显示了就ISE而言,静态(您可以说“ Java应用程序”或“ Java环境”状态)仍如何计为状态。
Andrew McNamee 2012年

@AndrewMcNamee我认为这AssertionError对于我知道自己搞砸了的情况更合适。这似乎是InternalError唯一的,因为它位于JDK代码而不是应用程序代码中-这是一个可疑的区别。
拉蒙2012年

是的,我绝对同意AssertionError;它似乎传达了“我搞砸了”,而不是“您搞砸了”(ISE暗示)。default对于switches,我经常使用它。国际海事组织InternalError仍然有帮助。阅读堆栈跟踪记录的人知道他们可以假设“哇,JDK搞砸了”,但是JDK的作者可能已经将其遗漏了。
安德鲁·麦克纳姆

2

我想如果您看到用法的话,IllegalStateException我会再说第二点。许多程序包中都使用了此异常

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

要指定一个示例,如果队列已满,则ArrayBlockingQueue.add引发此异常。现在,对象的状态已满,并且在不适当或非法的时间调用了该对象

我想两者的意思相同,但措辞有所不同。


1

给定一个库,它应该由于用户代码而在检测到错误时抛出一个IllegalStateExceptionIllegalArgumentException,而AssertionError由于库自身的实现,它应在检测到错误时抛出一个或。

例如,在库的测试中,您可能期望IllegalStateException当方法调用顺序错误时,库将引发。但是您永远都不会期望库会抛出一个AssertionError


0

这里没有“差异”。布洛赫(Bloch)的措辞没有什么可以排除JLS中所说的。Bloch只是在说,如果您有情况A,则抛出此异常。他并不是在这种情况下应该/应该抛出此异常。JLS说如果A,B或C抛出此异常。


我想你可以这么说。但另一方面,如果确实有与他所提供的使用环境不同的预期使用环境,那么这种可能性可能就没有那么有意义了,因为它不够具体。换句话说,如果打算将ISE用于当前的“您曾在我身上调用此方法,但我没有能力做到这一点”的情况,则它可能没有那么多信息。但不可否认,我想我是在这里劈头发;)
安德鲁·

@AndrewMcNamee我确实是这么说的。我不知道您的其余评论甚至意味着什么,但您正在尝试制造一个不存在的差异。您犯了逻辑上的谬误。
罗恩侯爵,

0

我遇到了这个问题:

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

我认为IllegalStateExceptionAssertionException即使这属于“ Java环境”类别,也不适合在这里扔掉。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.