Java - Eccezioni

Un'eccezione (o evento eccezionale) è un problema che sorge durante l'esecuzione di un programma. Quando unException si verifica il normale flusso del programma viene interrotto e il programma / applicazione termina in modo anomalo, il che non è consigliato, pertanto queste eccezioni devono essere gestite.

Un'eccezione può verificarsi per molti motivi diversi. Di seguito sono riportati alcuni scenari in cui si verifica un'eccezione.

  • Un utente ha inserito dati non validi.

  • Impossibile trovare un file che deve essere aperto.

  • Una connessione di rete è stata persa durante la comunicazione o la JVM ha esaurito la memoria.

Alcune di queste eccezioni sono causate da un errore dell'utente, altre da un errore del programmatore e altre da risorse fisiche che in qualche modo si sono guastate.

Sulla base di questi, abbiamo tre categorie di eccezioni. È necessario comprenderli per sapere come funziona la gestione delle eccezioni in Java.

  • Checked exceptions- Un'eccezione verificata è un'eccezione che viene controllata (notificata) dal compilatore in fase di compilazione, queste sono anche chiamate eccezioni in fase di compilazione. Queste eccezioni non possono essere semplicemente ignorate, il programmatore dovrebbe occuparsi di (gestire) queste eccezioni.

Ad esempio, se usi FileReaderclass nel programma per leggere i dati da un file, se il file specificato nel suo costruttore non esiste, si verifica un'eccezione FileNotFoundException e il compilatore richiede al programmatore di gestire l'eccezione.

Esempio

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

Se provi a compilare il programma precedente, otterrai le seguenti eccezioni.

Produzione

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 - Dal momento che i metodi read() e close() della classe FileReader genera IOException, puoi osservare che il compilatore notifica di gestire IOException, insieme a FileNotFoundException.

  • Unchecked exceptions- Un'eccezione non controllata è un'eccezione che si verifica al momento dell'esecuzione. Questi sono anche chiamati comeRuntime Exceptions. Questi includono bug di programmazione, come errori logici o uso improprio di un'API. Le eccezioni di runtime vengono ignorate al momento della compilazione.

Ad esempio, se è stato dichiarato un array di dimensione 5 nel programma, e cercando di chiamare il 6 ° elemento della matrice poi un ArrayIndexOutOfBoundsExceptionexception si verifica.

Esempio

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

Se compili ed esegui il programma precedente, otterrai la seguente eccezione.

Produzione

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
	at Exceptions.Unchecked_Demo.main(Unchecked_Demo.java:8)
  • Errors- Queste non sono affatto eccezioni, ma problemi che sorgono al di fuori del controllo dell'utente o del programmatore. Gli errori vengono generalmente ignorati nel codice perché raramente puoi fare qualcosa per un errore. Ad esempio, se si verifica un overflow dello stack, si verificherà un errore. Vengono ignorati anche al momento della compilazione.

Gerarchia delle eccezioni

Tutte le classi di eccezione sono sottotipi della classe java.lang.Exception. La classe di eccezione è una sottoclasse della classe Throwable. Oltre alla classe di eccezione, esiste un'altra sottoclasse chiamata Error che è derivata dalla classe Throwable.

Gli errori sono condizioni anomale che si verificano in caso di guasti gravi, questi non vengono gestiti dai programmi Java. Gli errori vengono generati per indicare gli errori generati dall'ambiente di runtime. Esempio: JVM ha esaurito la memoria. Normalmente, i programmi non possono recuperare da errori.

La classe Exception ha due sottoclassi principali: classe IOException e classe RuntimeException.

Di seguito è riportato un elenco delle eccezioni incorporate di Java selezionate e deselezionate più comuni .

Metodi di eccezioni

Di seguito è riportato l'elenco dei metodi importanti disponibili nella classe Throwable.

Sr.No. Metodo e descrizione
1

public String getMessage()

Restituisce un messaggio dettagliato sull'eccezione che si è verificata. Questo messaggio viene inizializzato nel costruttore Throwable.

2

public Throwable getCause()

Restituisce la causa dell'eccezione rappresentata da un oggetto Throwable.

3

public String toString()

Restituisce il nome della classe concatenata con il risultato di getMessage ().

4

public void printStackTrace()

Stampa il risultato di toString () insieme alla traccia dello stack su System.err, il flusso di output dell'errore.

5

public StackTraceElement [] getStackTrace()

Restituisce un array contenente ogni elemento nella traccia dello stack. L'elemento all'indice 0 rappresenta la parte superiore dello stack di chiamate e l'ultimo elemento dell'array rappresenta il metodo in fondo allo stack di chiamate.

6

public Throwable fillInStackTrace()

Riempie la traccia dello stack di questo oggetto Throwable con la traccia dello stack corrente, aggiungendo a qualsiasi informazione precedente nella traccia dello stack.

Catturare le eccezioni

Un metodo rileva un'eccezione utilizzando una combinazione di try e catchparole chiave. Un blocco try / catch viene posizionato attorno al codice che potrebbe generare un'eccezione. Il codice all'interno di un blocco try / catch viene definito codice protetto e la sintassi per l'utilizzo di try / catch è la seguente:

Sintassi

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

Il codice che è soggetto a eccezioni viene inserito nel blocco try. Quando si verifica un'eccezione, tale eccezione viene gestita dal blocco catch ad essa associato. Ogni blocco try dovrebbe essere immediatamente seguito da un blocco catch o infine da un blocco.

Un'istruzione catch implica la dichiarazione del tipo di eccezione che si sta tentando di intercettare. Se si verifica un'eccezione nel codice protetto, viene controllato il blocco (oi blocchi) catch che segue il tentativo. Se il tipo di eccezione che si è verificata è elencato in un blocco catch, l'eccezione viene passata al blocco catch proprio come un argomento viene passato in un parametro del metodo.

Esempio

Quello che segue è un array dichiarato con 2 elementi. Quindi il codice tenta di accedere al 3 ° elemento dell'array che genera un'eccezione.

// 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");
   }
}

Questo produrrà il seguente risultato:

Produzione

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

Blocchi multipli di cattura

Un blocco try può essere seguito da più blocchi catch. La sintassi per più blocchi catch è la seguente:

Sintassi

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

Le istruzioni precedenti mostrano tre blocchi di cattura, ma puoi averne un numero qualsiasi dopo un singolo tentativo. Se si verifica un'eccezione nel codice protetto, l'eccezione viene generata nel primo blocco catch nell'elenco. Se il tipo di dati dell'eccezione generata corrisponde a ExceptionType1, viene intercettato lì. In caso contrario, l'eccezione passa alla seconda istruzione catch. Ciò continua fino a quando l'eccezione non viene rilevata o non rientra in tutti i rilevamenti, nel qual caso il metodo corrente interrompe l'esecuzione e l'eccezione viene lanciata al metodo precedente nello stack di chiamate.

Esempio

Ecco un segmento di codice che mostra come utilizzare più istruzioni 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;
}

Cattura di più tipi di eccezioni

Poiché Java 7, è possibile gestire più di un'eccezione utilizzando un unico blocco catch, questa funzionalità semplifica il codice. Ecco come lo faresti -

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

Le parole chiave dei lanci / lanci

Se un metodo non gestisce un'eccezione verificata, il metodo deve dichiararlo utilizzando il throwsparola chiave. La parola chiave throws appare alla fine della firma di un metodo.

Puoi lanciare un'eccezione, una nuova istanziata o un'eccezione appena rilevata, utilizzando il throw parola chiave.

Cerca di capire la differenza tra le parole chiave throws e throw, throws viene utilizzato per posticipare la gestione di un'eccezione verificata e throw viene utilizzato per invocare esplicitamente un'eccezione.

Il metodo seguente dichiara che genera un'eccezione RemoteException:

Esempio

import java.io.*;
public class className {

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

Un metodo può dichiarare che genera più di un'eccezione, nel qual caso le eccezioni vengono dichiarate in un elenco separato da virgole. Ad esempio, il metodo seguente dichiara che genera un'eccezione RemoteException e un'eccezione InsufficientFundsException -

Esempio

import java.io.*;
public class className {

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

L'ultimo blocco

Il blocco finalmente segue un blocco try o un blocco catch. Un blocco di codice infine viene sempre eseguito, indipendentemente dal verificarsi di un'eccezione.

L'utilizzo di un blocco finalmente consente di eseguire qualsiasi istruzione di tipo cleanup che si desidera eseguire, indipendentemente da ciò che accade nel codice protetto.

Un blocco finalmente appare alla fine dei blocchi catch e ha la seguente sintassi:

Sintassi

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

Esempio

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

Questo produrrà il seguente risultato:

Produzione

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

Notare quanto segue:

  • Una clausola catch non può esistere senza un'istruzione try.

  • Non è obbligatorio avere clausole finalmente ogni volta che è presente un blocco try / catch.

  • Il blocco try non può essere presente senza la clausola catch o la clausola finalmente.

  • Non può essere presente alcun codice tra i blocchi try, catch, latest.

La prova con le risorse

Generalmente, quando usiamo risorse come stream, connessioni, ecc. Dobbiamo chiuderle esplicitamente utilizzando finalmente block. Nel seguente programma, stiamo leggendo i dati da un file utilizzandoFileReader e lo stiamo chiudendo usando finalmente block.

Esempio

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, indicato anche come automatic resource management, è un nuovo meccanismo di gestione delle eccezioni introdotto in Java 7, che chiude automaticamente le risorse utilizzate all'interno del blocco try catch.

Per utilizzare questa istruzione, è sufficiente dichiarare le risorse richieste tra parentesi e la risorsa creata verrà chiusa automaticamente alla fine del blocco. Di seguito è riportata la sintassi dell'istruzione try-with-resources.

Sintassi

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

Di seguito è riportato il programma che legge i dati in un file utilizzando l'istruzione try-with-resources.

Esempio

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

I seguenti punti devono essere tenuti a mente mentre si lavora con la dichiarazione try-with-resources.

  • Per usare una classe con l'istruzione try-with-resources dovrebbe essere implementata AutoCloseable l'interfaccia e il close() metodo di esso viene invocato automaticamente in fase di esecuzione.

  • È possibile dichiarare più di una classe nell'istruzione try-with-resources.

  • Mentre dichiari più classi nel blocco try dell'istruzione try-with-resources, queste classi vengono chiuse in ordine inverso.

  • Tranne la dichiarazione delle risorse tra parentesi, tutto è uguale al normale blocco try / catch di un blocco try.

  • La risorsa dichiarata in try viene istanziata appena prima dell'inizio del try-block.

  • La risorsa dichiarata nel blocco try viene implicitamente dichiarata come finale.

Eccezioni definite dall'utente

Puoi creare le tue eccezioni in Java. Tieni a mente i seguenti punti quando scrivi le tue classi di eccezioni:

  • Tutte le eccezioni devono essere figlio di Throwable.

  • Se si desidera scrivere un'eccezione selezionata che viene applicata automaticamente dalla regola Handle o Declare, è necessario estendere la classe Exception.

  • Se vuoi scrivere un'eccezione di runtime, devi estendere la classe RuntimeException.

Possiamo definire la nostra classe di eccezione come di seguito:

class MyException extends Exception {
}

Hai solo bisogno di estendere il predefinito Exceptionclass per creare la tua eccezione. Queste sono considerate eccezioni controllate. Il seguenteInsufficientFundsExceptionclass è un'eccezione definita dall'utente che estende la classe Exception, rendendola un'eccezione controllata. Una classe di eccezione è come qualsiasi altra classe, contenente campi e metodi utili.

Esempio

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

Per dimostrare l'utilizzo della nostra eccezione definita dall'utente, la seguente classe CheckingAccount contiene un metododraw () che genera un'eccezione 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;
   }
}

Il seguente programma BankDemo dimostra di invocare i metodi deposit () edraw () di 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();
      }
   }
}

Compila tutti i tre file precedenti ed esegui BankDemo. Questo produrrà il seguente risultato:

Produzione

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)

Eccezioni comuni

In Java, è possibile definire due categorie di eccezioni ed errori.

  • JVM Exceptions- Queste sono eccezioni / errori che vengono generati esclusivamente o logicamente dalla JVM. Esempi: NullPointerException, ArrayIndexOutOfBoundsException, ClassCastException.

  • Programmatic Exceptions- Queste eccezioni vengono generate esplicitamente dall'applicazione o dai programmatori API. Esempi: IllegalArgumentException, IllegalStateException.