可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
This came up in a discussion with a colleague today.
The Javadocs for Java's IllegalStateException
state that it:
Signals that a method has been invoked at an illegal or inappropriate time. In other words, the Java environment or Java application is not in an appropriate state for the requested operation.
And Effective Java says (Item 60, page 248):
Another commonly reused exception is IllegalStateException. This is generally the exception to throw if the invocation is illegal because of the state of the receiving object. For example, this would be the exception to throw if the caller attempted to use some object before it had been properly initialized.
It seems there's a bit of discrepancy here. The second sentence of the javadocs makes it sound like the exception could describe a very broad condition about the Java execution state, but the description in Effective Java makes it sound like it's used for conditions related specifically to the state of the state of the object whose method has been called.
The usages I've seen in the JDK (e.g. collections, Matcher
) and in Guava definitely seem to fall into the category that Effective Java talks about ("This object is in a state where this method can't be called"). This also seems consistent with IllegalStateException
's sibling IllegalArgumentException
.
Are there any legitimate IllegalStateException
usages in the JDK that do relate to the "Java environment" or "Java application"? Or do any best practices guides advocate using it for the broader execution state? If not, why the heck are the javadocs phrased like that? ;)
回答1:
Here is one particularly legitimate usage of this exception in JDK (see: URLConnection.setIfModifiedSince(long)
among 300+ other usages of it:
public void setIfModifiedSince(long ifmodifiedsince) {
if (connected)
throw new IllegalStateException("Already connected");
ifModifiedSince = ifmodifiedsince;
}
I think the example is pretty clear. If the object is in particular state ("Already connected"), some operations should not be called. In this case when connection was established, some properties cannot be set.
This exception is especially useful when your class has some state (state machine?) that changes over time, making some methods irrelevant or impossible. Think about a Car
class that has start()
, stop()
and fuel()
methods. While calling start()
twice, one after another, is probably nothing wrong, but fueling a started car is certainly a bad idea. Namely - car is in a wrong state.
Arguably good API should not allow us to call methods in wrong state so that problems like that are discovered at compile time, not at runtime. In this particular example connecting to a URL should return a different object with a subset of methods, all of which are valid after connecting.
回答2:
Here is an example in the JDK. There is a package private class called java.lang.Shutdown. If the system is shutting down and you attempt to add a new hook, it throws the IllegalStateException. One could argue that this meets the criteria of the "javadoc" guidance - since it is the Java environment that is in the wrong state.
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;
}
}
However it also illustrates that there really is no distinction between the "javadoc" guidance and the "Effective Java" guidance. Because of the way Shutdown is implemented, the shutdown-ness of the JVM is stored in a field called state. Therefore it also meets the "Effective Java" guidance for when to use IllegalStateException, since the "state" field is part of the state of the receiving object. Since the receiving object (Shutdown) is in the wrong state, it throws the IllegalStateException.
In my opinion the two descriptions of when to use IllegalStateException are consistent. The Effective Java description is a bit more practical, that's all. For most of us, the most important part of the entire Java environment is the class that we are writing right now, so that is what the author is focusing on.
回答3:
I guess if you see usage of IllegalStateException
I would say second if more appropriate. This exception is used in lot of packages
- java.net
- java.nio
- java.util
- java.util.concurrrent etc
To specify one example ArrayBlockingQueue.add throws this exception if queue is already full. Now full is state of the object and it is being invoked at inappropriate or Illegal time
I guess both means same but difference of wording.
回答4:
There is no 'discrepancy' here. There is nothing in Bloch's wording that excludes what it says in the JLS. Bloch is simply saying that if you have circumstance A, throw this exception. He is not saying that this exception is/should be thrown only in this condition. The JLS is saying this exception is thrown if A, B, or C.
回答5:
I ran into this with:
try {
MessageDigest digest = MessageDigest.getInstance("SHA-1");
...
} catch (NoSuchAlgorithmException e) {
throw new AssertionError(e);
}
I think it will be impractical for me to throw IllegalStateException
here in place of AssertionException
even though this falls into the "the Java environment" category.
回答6:
Given a library, it should throw an IllegalStateException
or IllegalArgumentException
whenever it detects a bug due to the user code, whereas the library should throw an AssertionError
whenever it detects a bug due to the library's own implementation.
For example, in the library's tests, you may expect the library throws an IllegalStateException
when the order of method calls are wrong. But you will never expect the library throws an AssertionError
.