Java - wyjątki

Wyjątkiem (lub wyjątkowym zdarzeniem) jest problem, który pojawia się podczas wykonywania programu. Kiedy plikException występuje, normalny przepływ programu zostaje zakłócony, a program / Aplikacja kończy się nieprawidłowo, co nie jest zalecane, dlatego te wyjątki powinny być obsługiwane.

Wyjątek może wystąpić z wielu różnych powodów. Poniżej przedstawiono kilka scenariuszy, w których występuje wyjątek.

  • Użytkownik wprowadził nieprawidłowe dane.

  • Nie można znaleźć pliku, który należy otworzyć.

  • Połączenie sieciowe zostało utracone w trakcie komunikacji lub w maszynie JVM zabrakło pamięci.

Niektóre z tych wyjątków są spowodowane błędem użytkownika, inne błędem programisty, a inne zasobami fizycznymi, które uległy awarii.

Na tej podstawie mamy trzy kategorie wyjątków. Musisz je zrozumieć, aby wiedzieć, jak działa obsługa wyjątków w Javie.

  • Checked exceptions- Sprawdzony wyjątek to wyjątek, który jest sprawdzany (powiadamiany) przez kompilator w czasie kompilacji, są one również nazywane wyjątkami czasu kompilacji. Tych wyjątków nie można po prostu zignorować, programista powinien się nimi zająć (obsłużyć).

Na przykład, jeśli używasz FileReaderklasy w programie do odczytu danych z pliku, jeśli plik określony w jego konstruktorze nie istnieje, pojawia się wyjątek FileNotFoundException i kompilator monituje programistę o obsłużenie wyjątku.

Przykład

import java.io.File;
import java.io.FileReader;

public class FilenotFound_Demo {

   public static void main(String args[]) {		
      File file = new File("E://file.txt");
      FileReader fr = new FileReader(file); 
   }
}

Jeśli spróbujesz skompilować powyższy program, uzyskasz następujące wyjątki.

Wynik

C:\>javac FilenotFound_Demo.java
FilenotFound_Demo.java:8: error: unreported exception FileNotFoundException; must be caught or declared to be thrown
      FileReader fr = new FileReader(file);
                      ^
1 error

Note - Od metod read() i close() klasy FileReader zgłasza IOException, można zauważyć, że kompilator powiadamia o obsłużeniu IOException wraz z FileNotFoundException.

  • Unchecked exceptions- Niezaznaczony wyjątek to wyjątek występujący w momencie wykonania. Są one również nazywane jakoRuntime Exceptions. Obejmują one błędy programistyczne, takie jak błędy logiczne lub nieprawidłowe użycie interfejsu API. Wyjątki środowiska uruchomieniowego są ignorowane w momencie kompilacji.

Na przykład, jeśli deklarują tablicę o rozmiarze 5 w swoim programie, a próby wywołania 6 th element tablicy wówczas ArrayIndexOutOfBoundsExceptionexception występuje.

Przykład

public class Unchecked_Demo {
   
   public static void main(String args[]) {
      int num[] = {1, 2, 3, 4};
      System.out.println(num[5]);
   }
}

Jeśli skompilujesz i uruchomisz powyższy program, otrzymasz następujący wyjątek.

Wynik

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
	at Exceptions.Unchecked_Demo.main(Unchecked_Demo.java:8)
  • Errors- To wcale nie są wyjątki, ale problemy, które powstają poza kontrolą użytkownika lub programisty. Błędy są zwykle ignorowane w kodzie, ponieważ rzadko można coś zrobić z błędem. Na przykład, jeśli nastąpi przepełnienie stosu, wystąpi błąd. Są również ignorowane podczas kompilacji.

Hierarchia wyjątków

Wszystkie klasy wyjątków są podtypami klasy java.lang.Exception. Klasa wyjątku jest podklasą klasy Throwable. Oprócz klasy wyjątków istnieje inna podklasa o nazwie Error, która wywodzi się z klasy Throwable.

Błędy to nienormalne warunki występujące w przypadku poważnych awarii, których nie obsługują programy Java. Błędy są generowane w celu wskazania błędów generowanych przez środowisko wykonawcze. Przykład: zabrakło pamięci w JVM. Zwykle programy nie mogą naprawić błędów.

Klasa Exception ma dwie główne podklasy: klasę IOException i klasę RuntimeException.

Poniżej znajduje się lista najczęściej zaznaczonych i niezaznaczonych wbudowanych wyjątków Java .

Metody wyjątków

Poniżej znajduje się lista ważnych metod dostępnych w klasie Throwable.

Sr.No. Metoda i opis
1

public String getMessage()

Zwraca szczegółowy komunikat o wystąpieniu wyjątku. Ta wiadomość jest inicjowana w konstruktorze Throwable.

2

public Throwable getCause()

Zwraca przyczynę wyjątku reprezentowaną przez obiekt Throwable.

3

public String toString()

Zwraca nazwę klasy połączoną z wynikiem getMessage ().

4

public void printStackTrace()

Wyświetla wynik metody toString () wraz ze śladem stosu do System.err, strumienia wyjściowego błędu.

5

public StackTraceElement [] getStackTrace()

Zwraca tablicę zawierającą każdy element ze śladu stosu. Element pod indeksem 0 reprezentuje górę stosu wywołań, a ostatni element w tablicy reprezentuje metodę na dole stosu wywołań.

6

public Throwable fillInStackTrace()

Wypełnia ślad stosu tego obiektu Throwable bieżącym śladem stosu, dodając do wszelkich poprzednich informacji w śladzie stosu.

Łapanie wyjątków

Metoda przechwytuje wyjątek przy użyciu kombinacji try i catchsłowa kluczowe. Blok try / catch jest umieszczany wokół kodu, który może generować wyjątek. Kod w bloku try / catch jest nazywany kodem chronionym, a składnia użycia try / catch wygląda następująco -

Składnia

try {
   // Protected code
} catch (ExceptionName e1) {
   // Catch block
}

Kod podatny na wyjątki jest umieszczony w bloku try. Gdy wystąpi wyjątek, ten wyjątek jest obsługiwany przez skojarzony z nim blok catch. Po każdym bloku try powinien natychmiast nastąpić blok catch lub blok na końcu.

Instrukcja catch obejmuje deklarowanie typu wyjątku, który próbujesz przechwycić. Jeśli w kodzie chronionym wystąpi wyjątek, sprawdzany jest blok (lub bloki) catch następujący po try. Jeśli typ wyjątku, który wystąpił, jest wymieniony w bloku catch, wyjątek jest przekazywany do bloku catch, podobnie jak argument jest przekazywany do parametru metody.

Przykład

Poniżej znajduje się tablica zadeklarowana z 2 elementami. Następnie kod próbuje uzyskać dostęp do 3 rd elementu tablicy, który zgłasza wyjątek.

// File Name : ExcepTest.java
import java.io.*;

public class ExcepTest {

   public static void main(String args[]) {
      try {
         int a[] = new int[2];
         System.out.println("Access element three :" + a[3]);
      } catch (ArrayIndexOutOfBoundsException e) {
         System.out.println("Exception thrown  :" + e);
      }
      System.out.println("Out of the block");
   }
}

To da następujący wynik -

Wynik

Exception thrown  :java.lang.ArrayIndexOutOfBoundsException: 3
Out of the block

Wiele bloków połowowych

Po bloku try może następować wiele bloków catch. Składnia wielu bloków catch wygląda następująco -

Składnia

try {
   // Protected code
} catch (ExceptionType1 e1) {
   // Catch block
} catch (ExceptionType2 e2) {
   // Catch block
} catch (ExceptionType3 e3) {
   // Catch block
}

Poprzednie instrukcje przedstawiają trzy bloki catch, ale po jednej próbie możesz mieć ich dowolną liczbę. Jeśli wyjątek wystąpi w chronionym kodzie, wyjątek zostanie zgłoszony do pierwszego bloku catch na liście. Jeśli typ danych zgłoszonego wyjątku jest zgodny z ExceptionType1, zostanie tam przechwycony. Jeśli nie, wyjątek jest przekazywany do drugiej instrukcji catch. Trwa to do momentu, gdy wyjątek zostanie przechwycony lub przepadnie przez wszystkie przechwytywania, w takim przypadku bieżąca metoda zatrzymuje wykonywanie, a wyjątek jest zgłaszany do poprzedniej metody na stosie wywołań.

Przykład

Oto segment kodu pokazujący, jak używać wielu instrukcji try / catch.

try {
   file = new FileInputStream(fileName);
   x = (byte) file.read();
} catch (IOException i) {
   i.printStackTrace();
   return -1;
} catch (FileNotFoundException f) // Not valid! {
   f.printStackTrace();
   return -1;
}

Wyłapywanie wielu typów wyjątków

Od wersji Java 7 można obsłużyć więcej niż jeden wyjątek za pomocą pojedynczego bloku catch, ta funkcja upraszcza kod. Oto, jak byś to zrobił -

catch (IOException|FileNotFoundException ex) {
   logger.log(ex);
   throw ex;

Słowa kluczowe rzuca / rzuca

Jeśli metoda nie obsługuje zaznaczonego wyjątku, metoda musi zadeklarować ją przy użyciu throwssłowo kluczowe. Słowo kluczowe throws pojawia się na końcu podpisu metody.

Możesz zgłosić wyjątek, nowo utworzony lub wyjątek, który właśnie został przechwycony, używając throw słowo kluczowe.

Spróbuj zrozumieć różnicę między słowami kluczowymi throws i throw, throws służy do odroczenia obsługi sprawdzanego wyjątku, a throw służy do jawnego wywołania wyjątku.

Poniższa metoda deklaruje, że zgłasza RemoteException -

Przykład

import java.io.*;
public class className {

   public void deposit(double amount) throws RemoteException {
      // Method implementation
      throw new RemoteException();
   }
   // Remainder of class definition
}

Metoda może zadeklarować, że zgłasza więcej niż jeden wyjątek, w którym to przypadku wyjątki są zadeklarowane na liście oddzielonej przecinkami. Na przykład poniższa metoda deklaruje, że zgłasza RemoteException i InsufficientFundsException -

Przykład

import java.io.*;
public class className {

   public void withdraw(double amount) throws RemoteException, 
      InsufficientFundsException {
      // Method implementation
   }
   // Remainder of class definition
}

Ostatni blok

Ostatni blok następuje po bloku try lub bloku catch. Ostateczny blok kodu zawsze jest wykonywany, niezależnie od wystąpienia wyjątku.

Korzystanie z bloku last umożliwia uruchamianie dowolnych instrukcji typu czyszczenia, które chcesz wykonać, bez względu na to, co dzieje się w chronionym kodzie.

Ostateczny blok pojawia się na końcu bloków catch i ma następującą składnię -

Składnia

try {
   // Protected code
} catch (ExceptionType1 e1) {
   // Catch block
} catch (ExceptionType2 e2) {
   // Catch block
} catch (ExceptionType3 e3) {
   // Catch block
}finally {
   // The finally block always executes.
}

Przykład

public class ExcepTest {

   public static void main(String args[]) {
      int a[] = new int[2];
      try {
         System.out.println("Access element three :" + a[3]);
      } catch (ArrayIndexOutOfBoundsException e) {
         System.out.println("Exception thrown  :" + e);
      }finally {
         a[0] = 6;
         System.out.println("First element value: " + a[0]);
         System.out.println("The finally statement is executed");
      }
   }
}

To da następujący wynik -

Wynik

Exception thrown  :java.lang.ArrayIndexOutOfBoundsException: 3
First element value: 6
The finally statement is executed

Zwróć uwagę na następujące kwestie -

  • Klauzula catch nie może istnieć bez instrukcji try.

  • Nie jest obowiązkowe umieszczanie klauzul końcowych za każdym razem, gdy obecny jest blok try / catch.

  • Blok try nie może być obecny bez klauzuli catch lub klauzuli last.

  • Żaden kod nie może znajdować się pomiędzy blokami try, catch, last.

Próba z zasobami

Ogólnie rzecz biorąc, kiedy używamy jakichkolwiek zasobów, takich jak strumienie, połączenia itp., Musimy je jawnie zamknąć, używając funkcji last block. W poniższym programie odczytujemy dane z pliku za pomocąFileReader i zamykamy go za pomocą final block.

Przykład

import java.io.File;
import java.io.FileReader;
import java.io.IOException;

public class ReadData_Demo {

   public static void main(String args[]) {
      FileReader fr = null;		
      try {
         File file = new File("file.txt");
         fr = new FileReader(file); char [] a = new char[50];
         fr.read(a);   // reads the content to the array
         for(char c : a)
         System.out.print(c);   // prints the characters one by one
      } catch (IOException e) {
         e.printStackTrace();
      }finally {
         try {
            fr.close();
         } catch (IOException ex) {		
            ex.printStackTrace();
         }
      }
   }
}

try-with-resources, zwany także automatic resource management, to nowy mechanizm obsługi wyjątków, który został wprowadzony w Javie 7, który automatycznie zamyka zasoby używane w bloku try catch.

Aby użyć tej instrukcji, wystarczy zadeklarować wymagane zasoby w nawiasach, a utworzony zasób zostanie automatycznie zamknięty na końcu bloku. Poniżej znajduje się składnia instrukcji try-with-resources.

Składnia

try(FileReader fr = new FileReader("file path")) {
   // use the resource
   } catch () {
      // body of catch 
   }
}

Poniżej znajduje się program, który odczytuje dane z pliku za pomocą instrukcji try-with-resources.

Przykład

import java.io.FileReader;
import java.io.IOException;

public class Try_withDemo {

   public static void main(String args[]) {
      try(FileReader fr = new FileReader("E://file.txt")) {
         char [] a = new char[50];
         fr.read(a);   // reads the contentto the array
         for(char c : a)
         System.out.print(c);   // prints the characters one by one
      } catch (IOException e) {
         e.printStackTrace();
      }
   }
}

Podczas pracy z instrukcją try-with-resources należy pamiętać o następujących kwestiach.

  • Aby użyć klasy z instrukcją try-with-resources, należy ją zaimplementować AutoCloseable interfejs i close() metoda jest wywoływana automatycznie w czasie wykonywania.

  • W instrukcji try-with-resources można zadeklarować więcej niż jedną klasę.

  • Podczas deklarowania wielu klas w bloku try instrukcji try-with-resources, klasy te są zamykane w odwrotnej kolejności.

  • Z wyjątkiem deklaracji zasobów w nawiasach, wszystko jest takie samo jak zwykły blok try / catch bloku try.

  • Zasób zadeklarowany w try zostanie utworzony tuż przed rozpoczęciem bloku try.

  • Zasób zadeklarowany w bloku try jest niejawnie deklarowany jako ostateczny.

Wyjątki zdefiniowane przez użytkownika

Możesz tworzyć własne wyjątki w Javie. Podczas pisania własnych klas wyjątków pamiętaj o następujących kwestiach -

  • Wszystkie wyjątki muszą być dzieckiem Throwable.

  • Jeśli chcesz napisać sprawdzony wyjątek, który jest automatycznie wymuszany przez regułę Handle lub Declare, musisz rozszerzyć klasę Exception.

  • Jeśli chcesz napisać wyjątek czasu wykonywania, musisz rozszerzyć klasę RuntimeException.

Możemy zdefiniować własną klasę wyjątków, jak poniżej -

class MyException extends Exception {
}

Wystarczy rozszerzyć predefiniowany plik Exceptionklasę, aby utworzyć własny wyjątek. Są one uważane za sprawdzone wyjątki. NastępująceInsufficientFundsExceptionclass to wyjątek zdefiniowany przez użytkownika, który rozszerza klasę Exception, czyniąc go sprawdzanym wyjątkiem. Klasa wyjątku jest jak każda inna klasa i zawiera przydatne pola i metody.

Przykład

// File Name InsufficientFundsException.java
import java.io.*;

public class InsufficientFundsException extends Exception {
   private double amount;
   
   public InsufficientFundsException(double amount) {
      this.amount = amount;
   }
   
   public double getAmount() {
      return amount;
   }
}

Aby zademonstrować użycie naszego wyjątku zdefiniowanego przez użytkownika, następująca klasa CheckingAccount zawiera metodę wycofania (), która zgłasza wyjątek InsufficientFundsException.

// File Name CheckingAccount.java
import java.io.*;

public class CheckingAccount {
   private double balance;
   private int number;
   
   public CheckingAccount(int number) {
      this.number = number;
   }
   
   public void deposit(double amount) {
      balance += amount;
   }
   
   public void withdraw(double amount) throws InsufficientFundsException {
      if(amount <= balance) {
         balance -= amount;
      }else {
         double needs = amount - balance;
         throw new InsufficientFundsException(needs);
      }
   }
   
   public double getBalance() {
      return balance;
   }
   
   public int getNumber() {
      return number;
   }
}

Poniższy program BankDemo demonstruje wywoływanie metod depozyt () i wycofanie () konta CheckingAccount.

// File Name BankDemo.java
public class BankDemo {

   public static void main(String [] args) {
      CheckingAccount c = new CheckingAccount(101);
      System.out.println("Depositing $500...");
      c.deposit(500.00);
      
      try {
         System.out.println("\nWithdrawing $100...");
         c.withdraw(100.00);
         System.out.println("\nWithdrawing $600...");
         c.withdraw(600.00);
      } catch (InsufficientFundsException e) {
         System.out.println("Sorry, but you are short $" + e.getAmount());
         e.printStackTrace();
      }
   }
}

Skompiluj wszystkie powyższe trzy pliki i uruchom BankDemo. To da następujący wynik -

Wynik

Depositing $500...

Withdrawing $100...

Withdrawing $600...
Sorry, but you are short $200.0
InsufficientFundsException
         at CheckingAccount.withdraw(CheckingAccount.java:25)
         at BankDemo.main(BankDemo.java:13)

Typowe wyjątki

W Javie można zdefiniować dwie kategorie Wyjątki i Błędy.

  • JVM Exceptions- Są to wyjątki / błędy, które są zgłaszane wyłącznie lub logicznie przez maszynę JVM. Przykłady: NullPointerException, ArrayIndexOutOfBoundsException, ClassCastException.

  • Programmatic Exceptions- Te wyjątki są jawnie zgłaszane przez aplikację lub programistów API. Przykłady: IllegalArgumentException, IllegalStateException.