1. Introducción
En programación a menudo hay situaciones en las que un método se encuentra con un error pero no sabe cómo manejarlo correctamente. Por ejemplo, un método lee un archivo, pero no sabe qué hacer si el archivo no existe: ¿preguntar al usuario? ¿Terminar el programa? ¿Probar con otro archivo? En tales casos, el método puede «trasladar la responsabilidad» a quien lo llamó —es decir, «propagar» la excepción a lo largo de la cadena de llamadas—.
Propagación de excepciones es un mecanismo que permite que un método no maneje el error por sí mismo, sino que avise al código invocador: «¡Tengo un problema aquí, resuélvelo tú!»
Analogía: Imagina que eres un agente de un call center. Te llama un cliente con una pregunta para la que no tienes respuesta. En lugar de adivinar, dices: «Un segundo, le paso con un especialista». Estás «propagando» la pregunta más allá.
La palabra clave throws: cómo funciona
En Java, para propagar excepciones se utiliza la palabra clave throws en la declaración del método.
Sintaxis:
return_type methodName(...) throws ExceptionType
{
// código del método
}
Después de throws se indica el tipo de excepción que puede producirse en ese método. Es como una advertencia para otros programadores: «¡Atención! Este método puede lanzar una excepción de tal tipo. ¡Estad preparados!»
Ejemplo:
public void readFile(String filename) throws FileNotFoundException
{
FileReader reader = new FileReader(filename); // puede lanzar FileNotFoundException
// ...
}
Aquí el método readFile no maneja el error por sí mismo, sino que informa: «Puedo lanzar FileNotFoundException — que decida quien me invoca qué hacer».
2. ¿Cómo debe reaccionar el método invocador?
Si llamas a un método que declara throws, tienes dos opciones:
- Manejar la excepción con try-catch
- Propagar también la excepción hacia arriba (añadir throws a tu propio método)
Opción 1: manejar con try-catch
public static void main(String[] args)
{
try
{
readFile("data.txt");
}
catch (FileNotFoundException e)
{
System.out.println("Archivo no encontrado: " + e.getMessage());
}
}
Aquí capturamos la excepción y decidimos qué hacer (por ejemplo, mostramos un mensaje al usuario).
Opción 2: propagarla más
public static void main(String[] args) throws FileNotFoundException
{
readFile("data.txt");
}
Ahora la responsabilidad de manejar el error recae en quien invoque a main (normalmente la propia JVM: si el error no se maneja, el programa finalizará mostrando un mensaje de error).
3. Ejemplo: lectura de un archivo con propagación de excepciones
Ejemplo completo con IOException y manejo a nivel de main:
import java.io.*;
public class FileDemo
{
// El método declara que puede lanzar IOException
public static void printFirstLine(String filename) throws IOException
{
BufferedReader reader = new BufferedReader(new FileReader(filename));
String line = reader.readLine();
System.out.println("Primera línea: " + line);
reader.close();
}
public static void main(String[] args)
{
try
{
printFirstLine("nofile.txt");
}
catch (IOException e)
{
System.out.println("Error al leer el archivo: " + e.getMessage());
}
}
}
El método printFirstLine no sabe qué hacer si el archivo no existe: simplemente propaga la excepción. En main capturamos el error y mostramos un mensaje.
4. Detalles útiles
¿Cuándo y por qué usar la propagación de excepciones?
- Cuando el método no puede o no debe decidir cómo manejar el error (por ejemplo, código de biblioteca).
- Cuando el manejo del error depende del contexto (en un caso terminar el programa, en otro — probar con otro archivo).
- Para no saturar el código con try-catch innecesarios donde no hace falta.
Mejor práctica: Propaga las excepciones si no puedes manejarlas de forma significativa. ¡No captures excepciones solo «por cumplir»!
Se pueden propagar varias excepciones
public void process() throws IOException, SQLException
{
// ...
}
Excepciones checked y unchecked: recordatorio
Checked exceptions (por ejemplo, IOException, SQLException) — el compilador exige que se manejen o se propaguen.
Unchecked exceptions (por ejemplo, NullPointerException, IllegalArgumentException) — el compilador no exige su manejo; no es necesario indicarlas en throws.
5. Errores típicos al propagar excepciones
Error n.º 1: olvidaste declarar throws para una excepción checked.
Si un método puede lanzar una excepción checked, pero no la declaras en throws ni la manejas mediante try-catch, el compilador emitirá un error.
Error n.º 2: capturas la excepción pero no la manejas.
Es una mala práctica escribir catch (Exception e) {}. Mejor propaga la excepción si no sabes qué hacer con ella.
Error n.º 3: propagas un tipo demasiado general.
Si el método solo puede lanzar FileNotFoundException, no escribas throws Exception: eso dificulta la comprensión del código.
Error n.º 4: incluyes excepciones unchecked en throws.
No tiene sentido escribir throws NullPointerException: el compilador no lo exige y no ayuda al manejo de errores.
GO TO FULL VERSION