Какое намеренное использование IllegalStateException?

Это появилось в дискуссии с коллегой сегодня.

Javadocs для Java IllegalStateException утверждают, что он:

Сигналы о том, что метод был вызван в незаконное или ненадлежащее время. Другими словами, среда Java или приложение Java не находятся в соответствующем состоянии для запрошенной операции.

И эффективная Java говорит (Пункт 60, страница 248):

Другим обычно используемым исключением является IllegalStateException. Это, как правило, исключение для броска, если вызов является незаконным из-за состояния принимающего объекта. Например, это было бы исключение для броска, если вызывающий пытался использовать какой-либо объект, прежде чем он был правильно инициализирован.

Кажется, здесь немного расхождения. Во втором предложении javadocs звучит так, что исключение может описывать очень широкое условие состояния выполнения Java, но описание в Effective Java делает его похожим на условия, связанные конкретно с состоянием состояния объекта, метод был вызван.

Устройства, которые я видел в JDK (например, коллекции, Matcher) и в Guava, определенно, похоже, относятся к категории, о которой говорит Effective Java ( "Этот объект находится в состоянии, когда этот метод не может быть называется" ). Это также похоже на IllegalStateException sibling IllegalArgumentException.

Существуют ли в JDK законные IllegalStateException -услуги, которые относятся к "среде Java" или "Java-приложению"? Или какие-либо рекомендации по лучшей практике пропагандируют его использование для более широкого состояния исполнения? Если нет, то почему это так называемые javadocs?;)

Ответ 1

Вот одно особенно законное использование этого исключения в 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-адресу должно возвращать другой объект с подмножеством методов, все из которых действительны после подключения.

Ответ 2

Вот пример в JDK. Существует пакет private class, называемый 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, shutdown-ness JVM хранится в поле с именем state. Поэтому он также отвечает указаниям "Эффективная Java", когда следует использовать IllegalStateException, поскольку поле "состояние" является частью состояния принимающего объекта. Поскольку принимающий объект (Shutdown) находится в неправильном состоянии, он выдает исключение IllegalStateException.

По-моему, два описания того, когда использовать IllegalStateException, являются последовательными. Эффективное описание Java немного более практично, все. Для большинства из нас наиболее важной частью всей среды Java является класс, который мы сейчас пишем, так что автор фокусируется на этом.

Ответ 3

Я предполагаю, что если вы видите использование IllegalStateException, я бы сказал, что второе, если это более уместно. Это исключение используется во многих пакетах

  • java.net
  • java.nio
  • java.util
  • java.util.concurrrent и т.д.

Чтобы указать один пример ArrayBlockingQueue.add выдает это исключение, если очередь уже заполнена. Теперь полное состояние объекта и оно вызывается в ненадлежащее или незаконное время

Я думаю, что оба варианта означают то же самое, но разницу в формулировках.

Ответ 4

Здесь нет "несоответствия". В блоховской формулировке нет ничего, что исключает то, что она говорит в JLS. Блох просто говорит, что если у вас есть обстоятельство А, выбросьте это исключение. Он не говорит, что это исключение/должно быть брошено только в этом состоянии. JLS говорит, что это исключение выбрасывается, если A, B или C.

Ответ 5

Я столкнулся с этим:

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

Я думаю, для меня будет нецелесообразно выбрасывать IllegalStateException вместо AssertionException, хотя это относится к категории "среда Java".

Ответ 6

Учитывая библиотеку, она должна бросать IllegalStateException или IllegalArgumentException всякий раз, когда обнаруживает ошибку из-за кода пользователя, тогда как библиотека должна бросать AssertionError всякий раз, когда обнаруживает ошибку из-за собственной реализации библиотеки.

Например, в тестах библиотеки вы можете ожидать, что библиотека выбрасывает IllegalStateException, когда порядок вызовов методов неверен. Но вы никогда не ожидаете, что библиотека выбрасывает AssertionError.