Java - Excepciones
Una excepción (o evento excepcional) es un problema que surge durante la ejecución de un programa. Cuando una Excepción ocurre, el flujo normal del programa se interrumpe y el programa/aplicación finaliza de manera anormal, lo cual no se recomienda, por lo tanto, estas excepciones deben manejarse.
Una excepción puede ocurrir por muchas razones diferentes. Los siguientes son algunos escenarios en los que se produce una excepción.
-
Un usuario ha introducido datos no válidos.
-
No se puede encontrar un archivo que debe abrirse.
-
Se ha perdido una conexión de red en medio de las comunicaciones o la JVM se ha quedado sin memoria.
Algunas de estas excepciones son causadas por errores del usuario, otras por errores del programador y otras por recursos físicos que han fallado de alguna manera.
En base a esto, tenemos tres categorías de Excepciones. Debe comprenderlos para saber cómo funciona el manejo de excepciones en Java.
-
Excepciones comprobadas − Una excepción verificada es una excepción que el compilador verifica (notifica) en el momento de la compilación; también se denominan excepciones de tiempo de compilación. Estas excepciones no pueden simplemente ignorarse, el programador debe cuidar (manejar) estas excepciones.
Por ejemplo, si usa FileReader class en su programa para leer datos de un archivo, si el archivo especificado en su constructor no existe, entonces una FileNotFoundException ocurre, y el compilador solicita al programador que maneje la excepción.
Ejemplo
Demostración en vivoimport 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); } }
Si intenta compilar el programa anterior, obtendrá las siguientes excepciones.
Salida
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
Nota − Dado que los métodos read() y cerrar() de la clase FileReader lanza IOException, puede observar que el compilador notifica para manejar IOException, junto con FileNotFoundException.
-
Excepciones no comprobadas − Una excepción no comprobada es una excepción que se produce en el momento de la ejecución. También se denominan Excepciones de tiempo de ejecución . Estos incluyen errores de programación, como errores lógicos o uso inadecuado de una API. Las excepciones de tiempo de ejecución se ignoran en el momento de la compilación.
Por ejemplo, si ha declarado una matriz de tamaño 5 en su programa e intenta llamar al 6 th elemento de la matriz y luego una excepción ArrayIndexOutOfBoundsException ocurre.
Ejemplo
Demostración en vivopublic class Unchecked_Demo { public static void main(String args[]) { int num[] = {1, 2, 3, 4}; System.out.println(num[5]); } }
Si compila y ejecuta el programa anterior, obtendrá la siguiente excepción.
Salida
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5 at Exceptions.Unchecked_Demo.main(Unchecked_Demo.java:8)
-
Errores − No se trata en absoluto de excepciones, sino de problemas que surgen fuera del control del usuario o del programador. Los errores generalmente se ignoran en su código porque rara vez puede hacer algo al respecto. Por ejemplo, si se produce un desbordamiento de pila, surgirá un error. También se ignoran en el momento de la compilación.
Jerarquía de excepciones
Todas las clases de excepción son subtipos de la clase java.lang.Exception. La clase de excepción es una subclase de la clase Throwable. Además de la clase de excepción, existe otra subclase llamada Error que se deriva de la clase Throwable.
Los errores son condiciones anormales que ocurren en caso de fallas severas, estos no son manejados por los programas Java. Los errores se generan para indicar errores generados por el entorno de tiempo de ejecución. Ejemplo:JVM no tiene memoria. Normalmente, los programas no pueden recuperarse de los errores.
La clase Exception tiene dos subclases principales:la clase IOException y la clase RuntimeException.
A continuación se muestra una lista de las excepciones integradas de Java marcadas y no marcadas más comunes.
Métodos de excepción
A continuación se muestra la lista de métodos importantes disponibles en la clase Throwable.
Sr.No. | Método y descripción |
---|---|
1 | Cadena pública getMessage() Devuelve un mensaje detallado sobre la excepción que se ha producido. Este mensaje se inicializa en el constructor Throwable. |
2 | obtenerCausa pública arrojable() Devuelve la causa de la excepción representada por un objeto Throwable. |
3 | Cadena pública aCadena() Devuelve el nombre de la clase concatenado con el resultado de getMessage(). |
4 | vacío público printStackTrace() Imprime el resultado de toString() junto con el seguimiento de la pila a System.err, el flujo de salida de error. |
5 | Public StackTraceElement [] getStackTrace() Devuelve una matriz que contiene cada elemento en el seguimiento de la pila. El elemento en el índice 0 representa la parte superior de la pila de llamadas y el último elemento de la matriz representa el método en la parte inferior de la pila de llamadas. |
6 | fillInStackTrace() público arrojable Rellena el seguimiento de la pila de este objeto Throwable con el seguimiento de la pila actual y se suma a cualquier información anterior en el seguimiento de la pila. |
Capturar excepciones
Un método detecta una excepción usando una combinación de try y atrapar palabras clave Se coloca un bloque try/catch alrededor del código que podría generar una excepción. El código dentro de un bloque try/catch se conoce como código protegido, y la sintaxis para usar try/catch es similar a la siguiente:
Sintaxis
try { // Protected code } catch (ExceptionName e1) { // Catch block }
El código que es propenso a excepciones se coloca en el bloque de prueba. Cuando ocurre una excepción, esa excepción es manejada por el bloque catch asociado a ella. Cada bloque de prueba debe ir seguido inmediatamente de un bloque de captura o de un bloque de finalización.
Una declaración de captura implica declarar el tipo de excepción que está tratando de capturar. Si se produce una excepción en el código protegido, se comprueba el bloque (o bloques) catch que sigue al intento. Si el tipo de excepción que ocurrió aparece en un bloque catch, la excepción se pasa al bloque catch de la misma manera que se pasa un argumento a un parámetro de método.
Ejemplo
La siguiente es una matriz declarada con 2 elementos. Entonces el código intenta acceder al 3 rd elemento de la matriz que lanza una excepción.
Demostración en vivo// 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"); } }
Esto producirá el siguiente resultado −
Salida
Exception thrown :java.lang.ArrayIndexOutOfBoundsException: 3 Out of the block
Múltiples bloques de captura
Un bloque de prueba puede ir seguido de varios bloques de captura. La sintaxis para varios bloques catch se parece a la siguiente −
Sintaxis
try { // Protected code } catch (ExceptionType1 e1) { // Catch block } catch (ExceptionType2 e2) { // Catch block } catch (ExceptionType3 e3) { // Catch block }
Las declaraciones anteriores demuestran tres bloques catch, pero puede tener cualquier cantidad de ellos después de un solo intento. Si ocurre una excepción en el código protegido, la excepción se lanza al primer bloque catch de la lista. Si el tipo de datos de la excepción lanzada coincide con ExceptionType1, se detecta allí. Si no, la excepción pasa a la segunda instrucción catch. Esto continúa hasta que la excepción se detecta o pasa por todas las capturas, en cuyo caso el método actual detiene la ejecución y la excepción se lanza al método anterior en la pila de llamadas.
Ejemplo
Aquí hay un segmento de código que muestra cómo usar varias instrucciones 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; }
Capturar varios tipos de excepciones
Desde Java 7, puede manejar más de una excepción usando un solo bloque catch, esta característica simplifica el código. Así es como lo harías −
catch (IOException|FileNotFoundException ex) { logger.log(ex); throw ex;
Los lanzamientos/Palabras clave de lanzamiento
Si un método no maneja una excepción verificada, el método debe declararlo usando los throws palabra clave. La palabra clave throws aparece al final de la firma de un método.
Puede lanzar una excepción, ya sea una recién instanciada o una excepción que acaba de capturar, usando el throw palabra clave.
Trate de entender la diferencia entre las palabras clave throws y throw, throws se usa para posponer el manejo de una excepción verificada y lanzar se utiliza para invocar una excepción explícitamente.
El siguiente método declara que lanza una RemoteException −
Ejemplo
import java.io.*; public class className { public void deposit(double amount) throws RemoteException { // Method implementation throw new RemoteException(); } // Remainder of class definition }
Un método puede declarar que arroja más de una excepción, en cuyo caso las excepciones se declaran en una lista separada por comas. Por ejemplo, el siguiente método declara que lanza una RemoteException y una InsufficientFundsException −
Ejemplo
import java.io.*; public class className { public void withdraw(double amount) throws RemoteException, InsufficientFundsException { // Method implementation } // Remainder of class definition }
El último bloque
El bloque finalmente sigue a un bloque de prueba o un bloque de captura. Un bloque de código finalmente siempre se ejecuta, independientemente de que ocurra una Excepción.
El uso de un bloque finalmente le permite ejecutar cualquier instrucción de tipo limpieza que desee ejecutar, sin importar lo que suceda en el código protegido.
Un bloque finalmente aparece al final de los bloques catch y tiene la siguiente sintaxis −
Sintaxis
try { // Protected code } catch (ExceptionType1 e1) { // Catch block } catch (ExceptionType2 e2) { // Catch block } catch (ExceptionType3 e3) { // Catch block }finally { // The finally block always executes. }
Ejemplo
Demostración en vivopublic 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"); } } }
Esto producirá el siguiente resultado −
Salida
Exception thrown :java.lang.ArrayIndexOutOfBoundsException: 3 First element value: 6 The finally statement is executed
Tenga en cuenta lo siguiente −
-
Una cláusula catch no puede existir sin una sentencia try.
-
No es obligatorio tener cláusulas finalmente siempre que esté presente un bloque try/catch.
-
El bloque try no puede estar presente sin la cláusula catch o la cláusulafinal.
-
Ningún código puede estar presente entre los bloques try, catch, finalmente.
Prueba-con-recursos
Generalmente, cuando usamos recursos como flujos, conexiones, etc., tenemos que cerrarlos explícitamente usando el bloque finalmente. En el siguiente programa, estamos leyendo datos de un archivo usando FileReader y lo estamos cerrando usando el bloque finalmente.
Ejemplo
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(); } } } }
probar-con-recursos , también conocido como gestión automática de recursos , es un nuevo mecanismo de manejo de excepciones que se introdujo en Java 7, que cierra automáticamente los recursos utilizados dentro del bloque try catch.
Para usar esta declaración, simplemente necesita declarar los recursos requeridos entre paréntesis, y el recurso creado se cerrará automáticamente al final del bloque. A continuación se muestra la sintaxis de la instrucción try-with-resources.
Sintaxis
try(FileReader fr = new FileReader("file path")) { // use the resource } catch () { // body of catch } }
A continuación se muestra el programa que lee los datos en un archivo utilizando la instrucción try-with-resources.
Ejemplo
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(); } } }
Se deben tener en cuenta los siguientes puntos al trabajar con la declaración de prueba con recursos.
-
Para usar una clase con declaración de prueba con recursos, debe implementar AutoCloseable interfaz y close() el método se invoca automáticamente en tiempo de ejecución.
-
Puede declarar más de una clase en la instrucción try-with-resources.
-
Mientras declara varias clases en el bloque de prueba de la declaración de prueba con recursos, estas clases se cierran en orden inverso.
-
Excepto la declaración de recursos entre paréntesis, todo es igual que el bloque try/catch normal de un bloque try.
-
El recurso declarado en try se instancia justo antes del inicio del bloque try.
-
El recurso declarado en el bloque try se declara implícitamente como final.
Excepciones definidas por el usuario
Puede crear sus propias excepciones en Java. Tenga en cuenta los siguientes puntos cuando escriba sus propias clases de excepción:
-
Todas las excepciones deben ser un hijo de Throwable.
-
Si desea escribir una excepción comprobada que se aplique automáticamente mediante la regla Manejar o declarar, debe ampliar la clase de excepción.
-
Si desea escribir una excepción de tiempo de ejecución, debe ampliar la clase RuntimeException.
Podemos definir nuestra propia clase de excepción como se muestra a continuación −
class MyException extends Exception { }
Solo necesita extender la Excepción predefinida clase para crear su propia excepción. Estas se consideran excepciones comprobadas. La siguiente Excepción de fondos insuficientes class es una excepción definida por el usuario que amplía la clase Exception, convirtiéndola en una excepción comprobada. Una clase de excepción es como cualquier otra clase y contiene campos y métodos útiles.
Ejemplo
// 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; } }
Para demostrar el uso de nuestra excepción definida por el usuario, la siguiente clase CheckingAccount contiene un método de retiro() que lanza una 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; } }
El siguiente programa BankDemo demuestra cómo invocar los métodos deposit() y retirar() de 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(); } } }
Compile los tres archivos anteriores y ejecute BankDemo. Esto producirá el siguiente resultado −
Salida
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)
Excepciones comunes
En Java, es posible definir dos categorías de Excepciones y Errores.
-
Excepciones de JVM − Estas son excepciones/errores que son exclusiva o lógicamente lanzados por la JVM. Ejemplos:NullPointerException, ArrayIndexOutOfBoundsException, ClassCastException.
-
Excepciones programáticas − Estas excepciones son lanzadas explícitamente por la aplicación o los programadores de la API. Ejemplos:IllegalArgumentException, IllegalStateException.
Java