Cuando trabajamos con Java, es fundamental saber cómo manejar situaciones en las que algo no sale como esperamos. Estas situaciones anómalas se conocen como excepciones, y para señalizarlas dentro de nuestro código contamos con dos palabras clave muy importantes: throw y throws. Aunque parezcan similares, tienen propósitos distintos y entender su uso correcto nos ayudará a escribir programas más robustos y claros.
Imaginemos que estamos desarrollando una aplicación que recopila datos estadísticos sobre la interacción del usuario, como el número de clics, páginas visitadas o sesiones activas. Estos datos los codificamos en una cadena de caracteres que queremos enviar a un servidor mediante un método llamado enviar. Aquí es donde el mundo exterior se vuelve impredecible: la conexión puede fallar, el servidor puede estar caído o el usuario puede no tener acceso a internet. Por eso, debemos estar preparados para detectar y manejar estas situaciones mediante excepciones.
Supongamos que queremos proteger nuestra API para que no se use incorrectamente, por ejemplo, evitando que se pase un parámetro nulo o una cadena vacía como codificación. En ese caso, podemos interrumpir la ejecución lanzando una excepción que indique que algo no está bien. Para lanzar una excepción en Java, primero necesitamos crear una instancia de una clase que extienda de Exception. Aunque podríamos usar Exception directamente, lo habitual es crear subclases específicas para representar distintos tipos de errores, lo que facilita su manejo posterior en bloques try-catch.
Las excepciones pueden llevar información adicional. Por ejemplo, podemos pasar un mensaje descriptivo que explique la razón del fallo, como la codificación está vacía. Este mensaje se puede recuperar con el método getMessage() para mostrarlo o registrarlo. Además, existe la posibilidad de encadenar excepciones usando un parámetro llamado causa (cause), que es otra excepción que originó el error actual. Esto nos permite construir una traza completa de errores, útil para depurar problemas complejos.
Una vez que tenemos la instancia de la excepción, la lanzamos con la palabra clave throw. Por ejemplo:
throw new Exception("la codificación está vacía");
Al usar throw, el flujo del programa se interrumpe, y el código que sigue no se ejecuta. Sin embargo, Java nos obliga a declarar en la firma del método qué excepciones pueden ser lanzadas, para que quien use ese método esté advertido y pueda manejar esos posibles errores. Aquí es donde entra la palabra clave throws. Por ejemplo, si nuestro método enviar puede lanzar una excepción, lo declaramos así:
public void enviar(String codificacion) throws Exception {
if (codificacion == null || codificacion.isEmpty()) {
throw new Exception("la codificación está vacía");
}
// lógica para enviar la codificación al servidor
}
Al declarar throws Exception, indicamos que este método puede lanzar una excepción que debe ser manejada por quien lo invoque. Esto obliga a que el código que llama a enviar utilice un bloque try-catch para capturar la excepción o también puede propagarla con su propio throws. Por ejemplo:
public static void main(String[] args) {
try {
enviar("");
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
}
Si optamos por no manejar la excepción en el método principal, podemos declararla con throws para que Java se encargue de terminar la ejecución si ocurre un error no controlado.
En resumen, throw es la instrucción que usamos para lanzar una excepción concreta en un punto del código, mientras que throws es la declaración que hacemos en la firma de un método para indicar que puede lanzar ciertas excepciones. Esta distinción es clave para que el manejo de errores en Java sea claro y efectivo, especialmente cuando interactuamos con recursos externos o condiciones que pueden fallar inesperadamente.
Además, entender cómo usar mensajes y causas en las excepciones nos permite crear sistemas de error más informativos y fáciles de depurar, lo que mejora la calidad y mantenibilidad de nuestros programas.