HOWTO · Java

RuntimeException en Java: significado, ejemplos y excepciones comprobadas

Aprende qué significa java.lang.RuntimeException en Java, conoce las causas comunes y compara las excepciones de tiempo de ejecución no comprobadas con las excepciones comprobadas.

En esta página

java.lang.RuntimeException es la clase base de Java para las excepciones no comprobadas. El compilador no exige que un método capture una de ellas ni que la declare con throws, pero un programa puede capturarla cuando la recuperación es apropiada. Las excepciones de tiempo de ejecución suelen señalar un defecto en la lógica del programa o una suposición que no se cumplió.

Comprender java.lang.RuntimeException en Java

Una excepción de tiempo de ejecución puede ocurrir mientras un programa se está ejecutando. Entre los ejemplos comunes se incluyen NullPointerException, ArrayIndexOutOfBoundsException y ArithmeticException. Sus nombres describen fallos diferentes:

  • Una NullPointerException puede ocurrir cuando el código desreferencia una referencia nula, como llamar a length() en una cadena nula.
  • Una ArrayIndexOutOfBoundsException puede ocurrir cuando el código lee o escribe en una posición de un arreglo inferior a cero o igual o mayor que la longitud del arreglo. Para un arreglo de longitud cinco, los índices válidos son de cero a cuatro.
  • Una ArithmeticException puede ocurrir cuando una división entera usa un divisor de cero. Esta afirmación se refiere a la división entera; la división en coma flotante entre cero sigue reglas diferentes en Java.

Estas excepciones no se limitan a un solo tipo de causa, y el hecho de que no sean comprobadas no significa que sea imposible manejarlas. Primero busca una forma de evitar el estado incorrecto: inicializa y valida las referencias, calcula los índices a partir de la longitud del arreglo y comprueba el divisor cuando cero no es un valor válido para la operación. Por ejemplo, un índice de arreglo es válido cuando se cumple index >= 0 && index < numbers.length.

Ejemplo

Este ejemplo completo valida cada entrada antes de usarla e imprime los valores resultantes.

public class RuntimeExceptionExample {
    public static void main(String[] args) {
        String text = "Java";
        int[] numbers = {10, 20, 30, 40, 50};
        int index = 2;
        int numerator = 12;
        int denominator = 3;

        if (text != null) {
            System.out.println("Text length: " + text.length());
        }

        if (index >= 0 && index < numbers.length) {
            System.out.println("Selected number: " + numbers[index]);
        }

        if (denominator != 0) {
            System.out.println("Quotient: " + numerator / denominator);
        }
    }
}
Text length: 4
Selected number: 30
Quotient: 4

La cadena está presente, el índice seleccionado está dentro del arreglo y el divisor es distinto de cero. Los casos de desreferencia nula, índice de arreglo no válido y divisor cero descritos aquí no se ejecutaron. Si se produce uno de esos fallos, se lanza la excepción de tiempo de ejecución correspondiente. Cuando una excepción no se captura, las sentencias posteriores a la operación que falló en esa ruta de ejecución no se ejecutan. Para demostrar cada fallo, cambia una entrada cada vez y trata ese caso por separado; no coloques varios fallos sin capturar en secuencia esperando que se alcance cada uno de ellos.

Capturar puede ser útil cuando el programa dispone de una acción de recuperación significativa, pero una captura amplia que simplemente oculta un defecto de programación dificulta el diagnóstico. Es preferible validar las entradas cerca del punto en que ingresan al programa y corregir la causa de los estados inesperados. Las pruebas y la depuración ayudan a encontrar esos defectos; las herramientas de análisis de código también pueden señalar algunos patrones riesgosos.

Diferencia entre java.lang.RuntimeException y java.lang.Exception

java.lang.RuntimeException extiende java.lang.Exception, por lo que toda excepción de tiempo de ejecución es también una excepción. Sin embargo, java.lang.Exception también tiene subclases comprobadas que no extienden RuntimeException. La distinción práctica es el requisito de manejo del compilador, no si la causa es externa ni si un desarrollador puede capturarla.

Una excepción comprobada debe capturarse o declararse en la cláusula throws del método. Por ejemplo, el código que llama a una API que declara una excepción comprobada debe tener en cuenta esa excepción para compilar. Para una excepción no comprobada como NullPointerException, Java no impone un requisito equivalente de captura o declaración. Tanto las excepciones comprobadas como las no comprobadas pueden capturarse con try y catch; capturar una excepción de tiempo de ejecución es apropiado cuando el código puede adoptar una acción de recuperación útil y bien definida.

Error es una rama separada bajo Throwable, no una subclase de Exception. Esta distinción ayuda a explicar por qué las reglas del compilador sobre excepciones comprobadas se aplican a los tipos de excepción distintos de las subclases de RuntimeException y de las subclases de Error.

Una excepción no capturada termina el hilo en el que se produce. Si escapa del hilo principal, la aplicación puede finalizar; una excepción no capturada en otro hilo no significa por sí misma que todos los hilos deban detenerse. El manejo debe ajustarse al fallo: recupérate cuando el programa tenga una vía de recuperación sólida y corrige los defectos que dejen el programa en un estado no deseado.

Conclusión

java.lang.RuntimeException no es comprobada, por lo que Java no exige que se capture ni se declare, aunque sí puede capturarse. Las desreferencias nulas, los índices de arreglo no válidos y la división entera entre cero son ejemplos comunes. Valida los valores y corrige el defecto subyacente cuando sea posible; usa un bloque catch cuando respalde una acción de recuperación clara. Recuerda que una excepción no capturada finaliza su hilo, mientras que el efecto sobre toda la aplicación depende de qué hilo haya fallado.