Prawo Murphy'ego: Każdy może ustalać nową regułę.
Java - Obsługa wyjątków w Javie
Podczas działania każdego programu mogą wystąpić błędy: wyjątki (ang. exceptions), jak np. dzielenie przez zero lub próba otwarcia nieistniejącego pliku. Java posiada mechanizm obsługi takich wyjątków poprzez wywoływaniem procedur obsługi błędów. wystąpienie błędu - wyjątku - powoduje przerwanie wykonywania programu. Mechanizm obsługi wyjątków umożliwia zaprogramowanie obsługi sytuacji błędnych, dzięki czemu program nie przerwie wykonywania po wystąpieniu błędu, ale może zignorować lub skorygować operację, która spowodowała wyjątek.

W Javie sytuacja wyjątkowa występuje wtedy, gdy program wykona instrukcję throw. Wyrażenie throw przekazuje sterowanie do skojarzonego z nim bloku catch: bloku obsługującego wystąpienie sytuacji wyjątkowej. Brak bloku catch w aktualnie wykonywanej metodzie powoduje przekazanie sterowania - bez zwracania wartości - do metody, która wywołała aktualną metodę. Jeśli w tej metodzie blok catch zostanie znaleziony, to jest on wykonywany. W przeciwnym razie sterowanie przekazywane jest do metody, która wywołała tę metodę zgodnie z łańcuchem wywołań metod. Dzieje się tak do momentu znalezienia bloku catch odpowiedzialnego za obsługę wyjątku.

Wszystkie wyjątki, które występują w programie muszą być podklasą klasy Throwable.

Struktura (fragmentu) programu z obsługą wyjątków:

   .....
   try
   {
        // ciąg instrukcji, które mogą spowodować wystąpienie wyjątku
   }

   catch (ObiektThrowable  nazwaZmiennej)
   {  // blok instrukcji obsługi sytuacji wyjątkowej
      // wykonywany tylko, gdy typu wyjątku jest identyczny
      // z typem zmiennej będącej parametrem bloku
   }

   catch (ObiektThrowable  nazwaZmiennej)
   {  . . . 
   } 

   catch (ObiektThrowable  nazwaZmiennej)
   {	. . . 
   } 

   finally      // opcjonalnie
   {  // blok instrukcji wykonywanych zawsze przed opuszczeniem metody 
      // również wtedy, gdy blok try zawiera instrukcję
      // return lub spowodował wystąpienie wyjątku
   }
   .....

Wystąpienie wyjątku powoduje wykonanie tylko jednego bloku catch. Ponieważ wyjątki mają różny "zasięg": od najogólniejszego: Exception, poprzez konkretne (IOException,...), aż po własne - zdefiniowane przez programistę, to należy pamiętać o umieszczeniu bloków obsługujących poszczególne sytuacje wyjątkowe w odpowiedniej kolejności: od najbardziej szczegółowych na początku, do najogólniejszych na końcu. W przeciwnym wypadku zawsze byłby wykonany blok najbardziej ogólny. Najczęściej jednak zła kolejność umieszczenia bloków catch wykrywana jest przez kompilator i sygnalizowania odpowiednim komunikatem błędu.

Przykład programu wywołującego sytuację wyjątkową:

   public class wyjatki
   {   public static void main (String args[])
      { Tab tab = new Tab();        // utworzenie obiektu klasy Tab

        for (int x=0 ; x<15 ; x++)  // wyświetlanie kolejnych
                                       // elementów tabeli
                                       // dla n=10 wystąpi błąd,
                                       // bo nie ma takiego elementu
            System.out.println("T[" + x + "] = " + tab.podajElement(x));
      }
   }

   class Tab
   {   int tab[];
       public Tab()                           // konstruktor klasy
       {   tab = new int[10];                  // tworzy tabelę o 10 elementach
           for (int i=0 ; i<10 ; i++)  tab[i] = i*i;
                                // przypisuje wartości elementom tabeli
       }

       int podajElement(int n)
       {   int retVal = 0;

           try                                 // zwraca element n
           {   retVal = tab[n];
           }
                            
           catch (ArrayIndexOutOfBoundsException  e)
                                          // wykonywane dla n > 9
           {  System.out.println("Nie ma elementu tabeli o numerze " + n);
              System.exit(1);
           }
           return retVal;
       }
   }

W powyższym przykładzie program dla n=10 wywoła procedurę obsługi wyjątków, która wyświetli stosowny komunikat i program zakończy działanie.

Spróbujmy jednak przerobić ten program tak, aby po wystąpieniu błędu pojawiał się tylko komunikat, ale program pracował nadal. W tym celu przeniesiemy procedurę obsługi błędu do metody main oraz dodamy metodę finally. Pozwoli to kontynuować program mimo wystąpienia kolejnych sytuacji wyjątkowych. W przykładzie tym utworzone są dwie procedury catch do obsługi błędu: 1-sz będzie wykonywana tylko wtedy, gdy podany indeks tablicy przekroczy dopuszczalny zakres; 2-ga - w każdym innym wypadku (w tym programie inny błąd nie może wystąpić, ale ma to być tylko przykład). Ważna jest przy tym kolejność obu procedur catch: gdybyśmy ja zmienili, to podczas kompilacji wystąpi błąd, ponieważ catch (Exception e) wyczerpuje wszystkie możliwe sytuacje wyjątkowe i umieszczenie za nią jakiejkolwiek innej procedury obsługi wyjątków jest błędem.

   public class wyjatki
   {   public static void main (String args[])
       {   Tab tab = new Tab();
          int x;
          for (int n=0 ; n<15 ; n++)
          {   try
             {   x = -1;
                 x = tab.podajElement(n);
             }

             catch (ArrayIndexOutOfBoundsException e)
             {   System.out.println("Nie ma elementu o numerze " + n);
             }

             catch (Exception e)
             {   System.out.println("Jakiś błąd!");
             }

             finally
             {   if (value!=-1)    System.out.println("Element nr 20 to: " + x);
             }
         }
      }
   }

   class Tab
   {  int tab[];
      public Tab()                    // konstruktor klasy
      {  tab = new int[10];           // tworzy tabelę o 10 elementach
         for (int i=0 ; i<10 ; i++)  tab[i] = i*i;
                                     // przypisuje wartości elementom tabeli
      }

      int podajElement(int n)
      {  return tab[n];              // zwraca n-ty element tabeli
                                     // dla n < 0 lub > 9 spowoduje błąd 
      }
   }
« wstecz   dalej »