2012-10-02 20 views
63

Ten temat pojawił się dziś w dyskusji z kolegą.Jakie jest zamierzone użycie wyjątku IllegalStateException?

Javadocs dla IllegalStateException stanu Java, że:

Sygnały, że metoda została przywołana w nielegalnym lub niewłaściwym czasie. Innymi słowy, środowisko Java lub aplikacja Java nie są w odpowiednim stanie dla żądanej operacji.

I Efektywna Java mówi (punkt 60, strona 248):

Innym powszechnie ponownie wykorzystane Wyjątkiem jest IllegalStateException. Jest to generalnie wyjątek do rzucania, jeśli wywołanie jest nielegalne z powodu stanu obiektu odbierającego. Na przykład byłby to wyjątek do rzucania, jeśli osoba wywołująca próbowała użyć jakiegoś obiektu, zanim został poprawnie zainicjowany.

Wygląda na to, że jest tu trochę rozbieżności. W drugim zdaniu javadocs brzmi to tak, jakby wyjątek mógł opisywać bardzo szeroki warunek dotyczący stanu wykonania Java, ale opis w Effective Java sprawia, że ​​brzmi on tak, jakby był używany w warunkach związanych konkretnie ze stanem stanu obiektu, którego metoda została wywołana.

Zastosowania, które widziałem w JDK (np. Kolekcje, Matcher) oraz w Guava zdecydowanie wydają się należeć do kategorii, o której mówi efektywna Java ("Ten obiekt jest w stanie, w którym ta metoda nie może być nazwana "). Wydaje się to również zgodne z rodzajem IllegalStateException rodzeństwa IllegalArgumentException.

Czy są jakieś uzasadnione zastosowania w JDK w zakresie IllegalStateException, które odnoszą się do "środowiska Java" lub "aplikacji Java"? Lub czy przewodniki najlepszych praktyk zalecają korzystanie z niego w szerszym stanie realizacji? Jeśli nie, dlaczego do cholery są sformułowane w ten sposób javadoki? ;)

+4

Być może nie ma to związku, zauważyłem, zauważyłem, że tag StackOverflow [nielegstatexception] mówi: "W Javie wyjątek, który występuje podczas używania wielu wątków, przy czym jeden wątek modyfikuje obiekt w sposób, który czyni go niekompatybilnym z użyciem tego obiektu w drugim wątku, w ten sposób wprowadzając przedmiot w nielegalne państwo. ". Huh? Skąd to pochodzi? –

+3

"Aplikacja Java" to ta, którą piszesz, i możesz użyć "IllegalStateException" (bezpośrednio lub z powodu używania Guava, na przykład). Gdzie ta rozbieżność? –

+4

Witryna tagów wygląda nieprawdopodobnie, przedłożyłam edycję, pożyczając od tego pytania swobodnie; powinieneś zobaczyć nową wersję po przejściu recenzji peer. – meriton

Odpowiedz

35

Oto jeden szczególnie uzasadnione wykorzystanie tego wyjątku w JDK (patrz: URLConnection.setIfModifiedSince(long) wśród ponad 300 innych zastosowań IT:

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

myślę, że przykład jest całkiem jasne, czy obiekt jest w szczególności. stan („już podłączony”), niektóre operacje nie powinny być nazywane. W tym przypadku, gdy połączenie zostało nawiązane, niektóre właściwości nie można ustawić.

wyjątek ten jest szczególnie przydatny, gdy klasa ma jakiś stan (machiny państwowej?), które zmieniają się w czasie, co powoduje, że niektóre metody są nieistotne t lub niemożliwe. Pomyśl o klasie Car, która ma metody start(), stop() i . Wywoływanie start() dwa razy, jeden po drugim, prawdopodobnie nie jest niczym złym, ale tankowanie uruchomionego samochodu jest z pewnością złym pomysłem. Mianowicie - samochód jest w złym stanie.

Niewłaściwie dobry interfejs API nie powinien pozwalać na wywoływanie metod w złym stanie, tak aby podobne problemy zostały wykryte podczas kompilacji, a nie w czasie wykonywania. W tym konkretnym przykładzie połączenie z adresem URL powinno zwrócić inny obiekt z podzbiorem metod, z których wszystkie są prawidłowe po nawiązaniu połączenia.

+1

Zgadzam się z twoją odpowiedzią. Ale to nie wyjaśnia, dlaczego Effectiva Java i Guava używają tego wyjątku jak '' IllegalArgumentException'' – Zarathustra

0

Zgaduję, że jeśli widzisz użycie IllegalStateException, powiedziałbym drugi, jeśli bardziej odpowiedni.Wyjątek ten jest stosowany w wielu pakietach

  • java.net
  • java.nio
  • java.util
  • java.util.concurrrent itp

Aby podać jeden przykład ArrayBlockingQueue.add rzuca ten wyjątek, jeśli kolejka jest już pełna. Teraz pełny jest stan obiektu i jest wywoływany w niewłaściwym lub nielegalnym czasie.

Sądzę, że oba oznaczają to samo, ale różnią się sformułowaniem.

4

Oto przykład w JDK. Istnieje pakiet klasy prywatnej o nazwie java.lang.shutdown. Jeśli system się wyłączy i spróbujesz dodać nowy hak, generuje wyjątek IllegalStateException. Można argumentować, że spełnia to kryteria poradnika "javadoc" - ponieważ jest to środowisko Java, które jest w złym stanie.

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; 
     } 
    } 

jednak ilustruje to również, że nie ma to żadnego rozróżnienia pomiędzy „javadoc” wskazówek i wytycznych „Efektywna Java”. Ze względu na sposób zamknięcia systemu zamykanie JVM jest przechowywane w polu o nazwie state. Dlatego też spełnia wytyczne "Efektywna Java", kiedy używać IllegalStateException, ponieważ pole "state" jest częścią stanu obiektu odbierającego. Ponieważ obiekt odbierający (Shutdown) jest w niewłaściwym stanie, generuje wyjątek IllegalStateException.

Moim zdaniem dwa opisy, kiedy należy korzystać z IllegalStateException są spójne. Efektywny opis Java jest nieco bardziej praktyczny, to wszystko. Dla większości z nas najważniejszą częścią całego środowiska Java jest klasa, którą teraz piszemy, więc na tym koncentruje się autor.

+1

Ach, podoba mi się ten przykład! Zwrot 'InternalError' tuż poniżej ISE pokazuje również, jak użyteczne jest dokonanie rozróżnienia" You messed up "vs" I him put up ". Pokazuje również, w jaki sposób stan statyczny (można powiedzieć "aplikacja Java" lub "środowisko Java") nadal jest uważany za stan w odniesieniu do ISE. –

+0

@AndrewMcNamee Myślę, że 'AssertionError' byłoby bardziej odpowiednie w przypadkach, w których wiem, że zawiedli. Wydaje się, że jest to "InternalError" tylko dlatego, że znajduje się wewnątrz kodu JDK, a nie kodu aplikacji - wątpliwe wyróżnienie. – Ramon

+0

Tak, zdecydowanie zgadzam się co do 'AssertionError'; wydaje się, że przekazuje "zepsute" w przeciwieństwie do "zawiedliście" (co sugeruje ISE). Używam go dużo w 'default' przypadku' switch'es. IMO 'InternalError' nadal służy użytecznemu celowi; osoba czytająca stosy wie, że może założyć "Whoa, JDK zawiedli", ale autorzy JDK prawdopodobnie mogliby go pominąć. –

0

Nie ma tu "rozbieżności". W słowach Blocha nie ma niczego, co wykluczałoby to, co mówi w JLS. Bloch mówi po prostu, że jeśli masz okoliczność A, wyrzuć ten wyjątek. Jest to , a nie, mówiąc, że ten wyjątek jest/powinien zostać odrzucony jako tylko w tym stanie. JLS mówi to jest wyjątek, jeśli A, B lub C.

+0

Przypuszczam, że można tak powiedzieć. Ale z drugiej strony, gdyby miał zamierzone okoliczności użycia, które różniłyby się od okoliczności, które podał, to może nie być tak znaczące, ponieważ byłoby mniej szczegółowe. Innymi słowy, jeśli ISE miały być używane w innych okolicznościach niż obecny "Wywołałeś tę metodę na mnie, ale nie jestem w stanie, w którym mogę to zrobić", to może nie być tak pouczające. Ale przyznaję, myślę, że dzielę włosy tutaj;) –

+0

@AndrewMcNamee I * tak * powiedziałem. Nie wiem, co oznacza jeszcze reszta twojego komentarza, ale próbujesz wytworzyć rozbieżność tam, gdzie nie istnieje. Popełniasz logiczny błąd. – EJP

0

wpadłem na to ze:

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

myślę będzie to niepraktyczne dla mnie rzucać IllegalStateException tutaj zamiast AssertionException nawet chociaż należy to do kategorii "środowisko Java".

0

Biorąc pod biblioteką, należy wyrzucić IllegalStateException lub IllegalArgumentException gdy wykryje błąd ze względu na kod użytkownika, natomiast biblioteka powinna rzucić AssertionError gdy wykryje błąd, z powodu własnej implementacji biblioteki.

Na przykład w testach biblioteki można oczekiwać, że biblioteka wyśle ​​IllegalStateException, gdy kolejność wywołań metod jest niepoprawna. Ale nigdy nie będziesz oczekiwać, że biblioteka wyrzuci numer AssertionError.

Powiązane problemy