Для чого призначене використання IllegalStateException?


76

Це виникла в ході дискусії з колегою сьогодні.

Javadocs для Java IllegalStateExceptionстверджує, що він:

Сигналізує про те, що метод був використаний у незаконний або невідповідний час. Іншими словами, середовище Java або програма Java не перебуває у відповідному стані для запитуваної операції.

І Ефективна Java говорить (Пункт 60, сторінка 248):

Іншим часто використовуваним винятком є ​​IllegalStateException. Як правило, це виняток для викиду, якщо виклик є незаконним через стан об’єкта, що отримує. Наприклад, це був би виняток для викиду, якщо абонент намагався використати якийсь об'єкт до того, як він був належним чином ініціалізований.

Здається, тут є трохи розбіжностей. Друге речення javadocs здається схожим на те, що виняток може описати дуже широку умову про стан виконання Java, але опис у Effective Java здається таким, що використовується для умов, що стосуються стану стану об'єкта, чий метод був названий.

Звичаї, які я бачив у JDK (наприклад, колекції Matcher) та в Гуаві, безумовно, потрапляють у категорію, про яку говорить Ефективна Java ("Цей об'єкт знаходиться у стані, коли цей метод не можна викликати"). Це також, здається, узгоджується з IllegalStateExceptionросійським братом або сестрою IllegalArgumentException.

Чи є IllegalStateExceptionв JDK якісь законні звичаї, які стосуються "середовища Java" або "програми Java"? Або будь-які посібники з найкращих практик виступають за його використання для більш широкого стану виконання? Якщо ні, чому, блін, javadocs так сформулювали? ;)


4
У примітці, можливо, не пов'язаній між собою, я помітив, що тег StackOverflow [незаконний_випуск] говорить 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там (або безпосередньо, або тому, що ви використовуєте Гуаву, наприклад). Де розбіжність?
Frank Pavageau

4
Тег wiki виглядає неправдиво, я подав редагування, щедро запозичивши це питання; Ви повинні побачити нову версію, як тільки вона пройде експертну перевірку.
meriton

Відповіді:


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 та Guava використовують цей виняток як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". Через те, як реалізовано вимкнення, вимикання JVM зберігається у полі, що називається стан. Тому він також відповідає керівництву "Ефективна Java" щодо того, коли використовувати IllegalStateException, оскільки поле "стан" є частиною стану об'єкта, що отримує. Оскільки отримуючий об'єкт (вимкнення) перебуває в неправильному стані, він викидає IllegalStateException.

На мій погляд, два описи, коли слід використовувати IllegalStateException, узгоджуються. Опис ефективного Java трохи практичніший, ось і все. Для більшості з нас найважливішою частиною всього середовища Java є клас, який ми пишемо зараз, тож саме на цьому автор зосереджується.


1
Ах, мені подобається цей приклад! InternalErrorКидок трохи нижче ISE також демонструє , наскільки це корисно зробити «Ви зіпсували» проти «я зіпсував» відмінність. Крім того, він показує, як статичний стан (можна сказати "Java-додаток" або "Java-середовище") все ще вважається станом, що стосується ISE.
Andrew McNamee,

@AndrewMcNamee Я думаю, що це AssertionErrorбуло б більш доречним для випадків, коли я знаю, що я переплутав. Здається, це InternalErrorлише тому, що він знаходиться всередині коду JDK, а не коду програми - сумнівна відмінність.
Рамон

Так, я безумовно погоджуюсь з цим AssertionError; здається, це передає "Я зіпсував" на відміну від "Ви зіпсували" (що передбачає ISE). Я багато використовую його у defaultвипадку для switches. ІМО InternalErrorвсе ще виконує корисні цілі; людина, яка читає трасування стека, знає, що вона може припустити "Ого, JDK переплутала", але автори JDK, можливо, могли це пропустити.
Ендрю МакНамі,

2

Я думаю, якщо ви бачите вживання, IllegalStateExceptionя б сказав, що друге, якщо це доречніше. Цей виняток використовується у багатьох пакетах

  • java.net
  • java.nio
  • java.util
  • java.util.concurrrent тощо

Щоб вказати один приклад, ArrayBlockingQueue.add видає цей виняток, якщо черга вже заповнена. Тепер повна - це стан об’єкта, і він викликається у невідповідний або незаконний час

Думаю, обидва означає однакові, але різниця в формулюванні.


1

Враховуючи бібліотеку, вона повинна видавати помилку IllegalStateExceptionабо IllegalArgumentExceptionколи вона виявляє помилку через код користувача, тоді як бібліотека повинна AssertionErrorвидавати помилку, коли виявляє помилку через власну реалізацію бібліотеки.

Наприклад, у тестах бібліотеки ви можете очікувати, що бібліотека видає, IllegalStateExceptionколи порядок викликів методів неправильний. Але ви ніколи не очікуєте, що бібліотека видасть файл AssertionError.


0

Тут немає "розбіжностей". У формулюванні Блоха немає нічого, що виключає те, що сказано в JLS. Блох просто говорить, що якщо у вас обставина A, киньте цей виняток. Він не говорить, що цей виняток є / повинен бути кинутий лише в такому стані. JLS заявляє, що цей виняток виникає, якщо A, B або C.


Думаю, ви могли б це сказати. Але з іншого боку, якби це передбачало обставини використання, які відрізнялися від обставини, яку він вказав, то це могло б бути не таким значущим, оскільки воно було б менш конкретним. Іншими словами, якщо ISE передбачалося використовувати за інших обставин, ніж поточний випадок "Ви закликали цей метод до мене, але я не в стані, коли я можу це зробити", це може бути не настільки інформативним. Але слід визнати, я думаю, що я тут розділюю волосся;)
Ендрю МакНамі,

@AndrewMcNamee Я це сказав. Я не знаю, що взагалі означає решта Вашого коментаря, але Ви намагаєтесь створити розбіжність там, де жодної не існує. Ви здійснюєте логічну помилку.
user207421

0

Я наткнувся на це з:

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

Думаю, для мене буде недоцільним кидати IllegalStateExceptionсюди замість того, AssertionExceptionхоча це потрапляє до категорії "середовище Java".

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.