9 Manejo de excepciones.
9.1 Introducción
El manejo de excepciones en Java es una característica fundamental que permite gestionar errores durante la ejecución de un programa, evitando que se interrumpa abruptamente. Las excepciones representan condiciones inusuales o errores que pueden ocurrir, como intentos fallidos de abrir un archivo o la entrada de datos inválidos.
9.2 Conceptos Básicos
9.2.1 ¿Qué es una excepción?
Una excepción es un evento que ocurre durante la ejecución de un programa y que interrumpe el flujo normal de las instrucciones. En Java, todas las excepciones son objetos que heredan de la clase base Throwable
.
Muchas clases de errores pueden provocar una excepción, desde un desbordamiento de memoria o un disco duro estropeado, un intento de dividir por cero, o intentar acceder a un vector fuera de sus límites Cuando esto ocurre, java crea un objeto de la clase exceptión
Ejemplo:
public class EjemploExcepciones{
public static void main (String[] args) {
int num1= 2, num2=0;
int result=num1/num2;
System.out.println("El resultado es: " + result);
}
}
9.2.2 Excepciones Propias de java
Antes de continuar, se debe conocer que java error y excepción son términos relacionados con problemas que pueden ocurrir durante la ejecución de un programa, pero tienen diferencias importantes en su naturaleza y manejo:
9.2.2.1 Error:
- Un error es un problema grave que ocurre fuera del control del programa y generalmente indica un fallo crítico del sistema o del entorno de ejecución.
Características:
-Representado por la clase Error, que es parte del paquete java.lang.
-No está diseñado para ser manejado por el programa.
En la mayoría de los casos, intentar capturar o recuperar un error es inútil.
Ejemplos comunes incluyen:
-StackOverflowError: Cuando se desborda la pila debido a una recursión excesiva.
-OutOfMemoryError: Cuando la JVM no tiene suficiente memoria para continuar.
Son más relacionados con el entorno de ejecución o la configuración del sistema.
9.2.2.2 Excepción:
Una excepción es un problema que ocurre durante la ejecución del programa debido a errores de lógica o circunstancias excepcionales predecibles.
Representada por la clase Exception, que es una subclase de Throwable, Está diseñada para ser manejada por el programa mediante bloques try-catch o con la cláusula throws.
Se divide en dos tipos:
-Verificadas en tiempo de compilación:
-No Verificadas en tiempo de compilación y suelen deberse a errores de programación:
Todos vienen de la clase throwable como se observa en la siguiente imagen.
9.2.3 Jerarquía de Excepciones
Throwable
: Clase base de todas las excepciones y errores.Exception
: Errores que pueden ser manejados por el programa.IOException
: Relacionadas con operaciones de entrada/salida.SQLException
: Errores en bases de datos.FileNotFoundException
: Archivo no encontrado.ArithmeticException
: Errores matemáticos como división por cero.
Error
: Condiciones críticas del sistema, como falta de memoria, que no deben manejarse directamente.
Ejemplos de Errores
StackOverflowError: Este error ocurre cuando un programa utiliza demasiada memoria en la pila debido a una recursión infinita o excesiva.
public class StackOverflowExample {
public static void main(String[] args) {
recursiveMethod(); // Llamada recursiva infinita
}
public static void recursiveMethod() {
recursiveMethod(); // Llamada a sí misma sin condición de salida
}
}
- OutOfMemoryError: Este error ocurre cuando la Java virtual machine (JVM) no tiene suficiente memoria para asignar nuevos objetos en el heap.
import java.util.ArrayList;
public class OutOfMemoryExample {
public static void main(String[] args) {
ArrayList<int[]> memoryHog = new ArrayList<>();
while (true) {
.add(new int[1_000_000]); // Intenta llenar el heap
memoryHog}
}
}
9.2.4 Ejemplo de Excepciones
Uso de
throw
Ejemplo lanzando una excepción
import java.io.FileReader;
public class Throws {
public static void main(String[] args) {
FileReader archivo = new FileReader("archivo_inexistente.txt"); // Puede lanzar FileNotFoundException
System.out.println("Archivo abierto con éxito.");
}
}
saldrá el siguiente mensaje: Exception in thread “main” java.lang.RuntimeException: Uncompilable code - unreported exception java.io.FileNotFoundException; must be caught or declared to be thrown at exepciones.Exepciones.main(
Español: Excepción en el hilo “main” java.lang.RuntimeException: Código no compilable - excepción no reportada java.io.FileNotFoundException; debe ser capturada o declarada para lanzarse en exepciones.Exepciones.main(
Ejemplo: Si ahora sólo lanzaramos la excepción con la palabra throws obtendríamos el siguiente mensaje.
import java.io.FileNotFoundException;
import java.io.FileReader;
public class Exepciones {
public static void main(String[] args) throws FileNotFoundException {
FileReader archivo = new FileReader("archivo_inexistente.txt"); // Puede lanzar FileNotFoundException
System.out.println("Archivo abierto con éxito.");
}
}
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.BufferedReader;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws FileNotFoundException, IOException {
// Intentar abrir el archivo
FileReader archivo = new FileReader("archivo_inexistente.txt");
BufferedReader bufferedReader = new BufferedReader(archivo);
// Leer el archivo línea por línea
String linea;
while ((linea = bufferedReader.readLine()) != null) {
System.out.println(linea); // Imprime cada línea
}
System.out.println("Archivo abierto con éxito.");
// Cerrar los recursos
.close();
bufferedReader.close();
archivo}
}
Exception in thread “main” java.io.FileNotFoundException: archivo_inexistente.txt (El sistema no puede encontrar el archivo especificado).
9.2.5 Ejemplo de Excepciones Manejando TRY-CATCH-FINALLY
El manejo de excepciones en Java se realiza utilizando los bloques try
, catch
, finally
, y throw
. Estos permiten controlar el flujo del programa y tomar acciones específicas cuando ocurre una excepción.
try
: Se utiliza para envolver el código que podría generar una excepción.catch
: Captura la excepción y permite tomar medidas para manejarla.finally
: Es un bloque opcional que se ejecuta después deltry
ycatch
, sin importar si se lanzó una excepción o no. Se usa generalmente para liberar recursos.throw
: Permite lanzar una excepción de manera manual.
Uso de try
y catch
Ejemplo básico:
public class EjemploExcepciones {
public static void main(String[] args) {
try {
int resultado = 10 / 0; // Esto genera una ArithmeticException
} catch (ArithmeticException e) {
System.out.println("Error: División por cero.");
} finally {
System.out.println("Operación finalizada.");
}
}
}
Sin excepción
public class EjemploExcepciones{
public static void main (String[] args) {
int num1= 2, num2=0;
int result=num1/num2;
System.out.println("El resultado es: " + result);
}
}
9.2.6 Captura de Múltiples Excepciones:
En Java, es posible capturar múltiples excepciones en un mismo bloque try-catch
, lo que facilita el manejo de diferentes tipos de errores en una misma sección de código. Desde Java 7, también se permite combinar varias excepciones en un solo bloque catch
usando el operador |
.
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
try {
System.out.print("Ingrese el numerador: ");
int numerador = scanner.nextInt();
System.out.print("Ingrese el denominador: ");
int denominador = scanner.nextInt();
int resultado = numerador / denominador;
System.out.println("Resultado: " + resultado);
} catch (ArithmeticException e) {
System.out.println("Error: El denominador no puede ser 0. Inténtalo de nuevo con un valor distinto.");
} catch (java.util.InputMismatchException e) { // java.util.InputMismatchExceptio se lanza cuando se intenta leer un tipo de dato que no coincide con el tipo esperado.
System.out.println("Error: Entrada inválida. Solo se permiten números enteros.");
}
}
}
Que pasaría ahora si se lanzara dentro de un bucle ejemplo while, para que se repita, si el usuario coloca mál el dato seguirá repitiendo la solicitud hasta tener datos correctos.
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
boolean entradaValida = false; // Bandera para controlar el bucle
while (!entradaValida) {
try {
System.out.print("Ingrese el numerador: ");
int numerador = scanner.nextInt();
System.out.print("Ingrese el denominador: ");
int denominador = scanner.nextInt();
if (denominador == 0) {
throw new ArithmeticException("El denominador no puede ser 0.");
}
int resultado = numerador / denominador;
System.out.println("Resultado: " + resultado);
= true; // Si llega aquí, las entradas son válidas
entradaValida
} catch (ArithmeticException e) {
System.out.println("Error: " + e.getMessage());
.nextLine(); // Limpiar el buffer de entrada
scanner} catch (java.util.InputMismatchException e) {
System.out.println("Error: Entrada inválida. Solo se permiten números enteros.");
.nextLine(); // Limpiar el buffer de entrada
scanner}
}
.close();
scanner}
}
Bloque Finally
El bloque finally
se utiliza en Java para ejecutar código que debe correr sin importar si se lanzó o no una excepción. Es útil para liberar recursos, como cerrar un objeto Scanner
.
En este caso, podemos usar finally
para garantizar que el objeto Scanner
se cierre después de que el programa haya terminado de procesar las entradas.
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in); // Crear el Scanner
try {
boolean entradaValida = false; // Bandera para controlar el bucle
while (!entradaValida) {
try {
System.out.print("Ingrese el numerador: ");
int numerador = scanner.nextInt();
System.out.print("Ingrese el denominador: ");
int denominador = scanner.nextInt();
if (denominador == 0) {
throw new ArithmeticException("El denominador no puede ser 0.");
}
int resultado = numerador / denominador;
System.out.println("Resultado: " + resultado);
= true; // Entrada válida, salir del bucle
entradaValida
} catch (ArithmeticException e) {
System.out.println("Error: " + e.getMessage());
.nextLine(); // Limpiar el buffer de entrada
scanner} catch (java.util.InputMismatchException e) {
System.out.println("Error: Entrada inválida. Solo se permiten números enteros.");
.nextLine(); // Limpiar el buffer de entrada
scanner}
}
} finally {
.close(); // Garantiza que el recurso Scanner se cierra
scannerSystem.out.println("Recurso Scanner cerrado.");
}
}
}
9.2.7 Diferencias Clave entre los programas anteriores
Característica | Primer Código (con finally ) |
Segundo Código (sin finally ) |
---|---|---|
Uso de finally |
Utiliza el bloque finally para garantizar el cierre del recurso Scanner . |
No usa finally , pero cierra el recurso manualmente al final. |
Liberación de Recursos | El cierre del Scanner ocurre siempre, incluso si ocurre una excepción. |
El cierre del Scanner depende de que el flujo salga del bucle correctamente. |
Robustez del Código | Más robusto, ya que garantiza que el Scanner siempre se cierre. |
Menos robusto, podría no cerrar el recurso si ocurre un error inesperado fuera del bucle. |
Legibilidad | Separa claramente la lógica del cierre de recursos en el bloque finally . |
Agrupa todo en el flujo principal, lo que puede ser más legible en casos simples. |
Video de refuerzo
https://www.youtube.com/watch?v=VHy6xFXJ1Rw