Manejo de errores básico

Intermedio
Java
Java
Actualizado: 28/08/2025

Comprensión de errores de compilación

Los errores de compilación son problemas que impiden que el compilador de Java transforme el código fuente en bytecode ejecutable. A diferencia de los errores que ocurren durante la ejecución del programa, estos errores se detectan antes de que el programa pueda ejecutarse, lo que nos permite identificar y corregir problemas estructurales y sintácticos de forma temprana.

Naturaleza de los errores de compilación

Los errores de compilación representan violaciones de las reglas sintácticas y semánticas de Java. El compilador javac analiza minuciosamente cada línea de código y reporta cualquier inconsistencia con la especificación del lenguaje. Estos errores son determinísticos: si existe un error de compilación, el programa no se ejecutará hasta que se resuelva.

El compilador de Java proporciona mensajes descriptivos que incluyen el archivo, la línea específica donde se detectó el error y una descripción del problema. Esta información es fundamental para localizar y corregir rápidamente los errores.

Categorías principales de errores de compilación

  • 1. Errores sintácticos

Los errores sintácticos ocurren cuando el código no sigue la estructura gramatical correcta de Java. Son los más comunes entre programadores principiantes:

public class EjemploSintaxis {
    public static void main(String[] args) {
        int numero = 10  // Error: falta punto y coma
        System.out.println(numero);
    } // Error: llave de cierre mal posicionada
  • 2. Errores de tipos de datos

Java es un lenguaje fuertemente tipado, lo que significa que cada variable debe tener un tipo específico y las operaciones entre tipos incompatibles generan errores:

public class EjemploTipos {
    public static void main(String[] args) {
        int edad = "25";        // Error: incompatibilidad de tipos
        String nombre = 42;     // Error: no se puede asignar int a String
        boolean activo = "si";  // Error: String no es boolean
    }
}
  • 3. Errores de declaración de variables

Estos errores surgen por problemas en la declaración o inicialización de variables:

public class EjemploVariables {
    public static void main(String[] args) {
        int x;
        int y = x + 5;          // Error: variable x no inicializada
        
        int numero = 10;
        int numero = 20;        // Error: variable ya declarada
        
        System.out.println(z);  // Error: variable z no declarada
    }
}

Errores relacionados con métodos y clases

Los errores de compilación también aparecen cuando hay problemas con la estructura de clases y métodos:

  • 4. Errores de modificadores de acceso
public class EjemploAcceso {
    private int valor = 100;
    
    public static void main(String[] args) {
        EjemploAcceso obj = new EjemploAcceso();
        System.out.println(valor);  // Error: acceso a variable no estática desde contexto estático
    }
}
  • 5. Errores de métodos
public class EjemploMetodos {
    public int calcular(int a, int b) {
        // Error: método debe devolver un valor
    }
    
    public static void main(String[] args) {
        calcular(5, 3);  // Error: método no estático llamado desde contexto estático
    }
}

Interpretación de mensajes del compilador

El compilador de Java genera mensajes específicos que siguen un patrón estructurado. Un mensaje típico incluye:

NombreArchivo.java:línea: error: descripción del error
    código problemático
    ^

Por ejemplo:

Calculadora.java:8: error: cannot find symbol
        System.out.println(resultado);
                           ^
  symbol:   variable resultado
  location: class Calculadora

Este mensaje indica que en la línea 8 del archivo Calculadora.java existe una variable llamada resultado que no ha sido declarada en el ámbito actual.

Estrategias para resolver errores de compilación

La resolución efectiva de errores de compilación requiere un enfoque sistemático:

  • 1. Leer cuidadosamente el mensaje de error

El compilador proporciona información precisa sobre la naturaleza del problema. No ignorar los detalles del mensaje puede ahorrar tiempo considerable.

  • 2. Verificar la sintaxis básica

Comprobar que todas las llaves, paréntesis y punto y coma estén correctamente colocados:

public class VerificarSintaxis {
    public static void main(String[] args) {
        if (true) {
            System.out.println("Correcto");
        } // Verificar que cada llave de apertura tenga su cierre
    }
}
  • 3. Revisar los tipos de datos

Asegurar que las asignaciones y operaciones se realicen entre tipos compatibles:

public class VerificarTipos {
    public static void main(String[] args) {
        int edad = 25;              // Correcto: int a int
        String mensaje = "Hola";    // Correcto: String a String
        double precio = edad;       // Correcto: conversión implícita válida
    }
}

Los errores de compilación, aunque pueden resultar frustrantes inicialmente, representan una ventaja del sistema de tipos de Java. Detectar errores antes de la ejecución evita problemas más complejos durante el funcionamiento del programa y facilita el mantenimiento del código a largo plazo.

Errores en tiempo de ejecución

Los errores en tiempo de ejecución (runtime errors) son problemas que surgen mientras el programa se está ejecutando, después de que el código ha compilado correctamente. A diferencia de los errores de compilación, estos errores no impiden que el programa inicie, pero pueden causar que se detenga abruptamente durante su ejecución o produzca resultados inesperados.

Características de los errores en tiempo de ejecución

Los errores en tiempo de ejecución se manifiestan como excepciones que interrumpen el flujo normal del programa. Java representa estos errores mediante objetos de la clase Exception y sus subclases. Cuando ocurre un error en tiempo de ejecución, la máquina virtual de Java (JVM) crea un objeto de excepción que contiene información detallada sobre el error.

La principal característica de estos errores es que son impredecibles durante la fase de compilación. El compilador no puede anticipar todas las situaciones que pueden ocurrir durante la ejecución, como intentar acceder a un archivo que no existe o dividir entre cero.

Tipos principales de errores en tiempo de ejecución

  • 1. NullPointerException

Es la excepción más común en Java. Ocurre cuando se intenta utilizar una referencia que apunta a null:

public class EjemploNullPointer {
    public static void main(String[] args) {
        String texto = null;
        System.out.println(texto.length()); // Lanza NullPointerException
    }
}
  • 2. ArrayIndexOutOfBoundsException

Se produce cuando se intenta acceder a una posición inválida de un array:

public class EjemploArrayIndex {
    public static void main(String[] args) {
        int[] numeros = {1, 2, 3};
        System.out.println(numeros[5]); // Lanza ArrayIndexOutOfBoundsException
    }
}
  • 3. ArithmeticException

Ocurre durante operaciones matemáticas incorrectas, como la división entre cero:

public class EjemploAritmetica {
    public static void main(String[] args) {
        int resultado = 10 / 0; // Lanza ArithmeticException
        System.out.println(resultado);
    }
}
  • 4. NumberFormatException

Se genera cuando se intenta convertir una cadena a un tipo numérico, pero la cadena no tiene un formato válido:

public class EjemploNumberFormat {
    public static void main(String[] args) {
        String texto = "abc";
        int numero = Integer.parseInt(texto); // Lanza NumberFormatException
        System.out.println(numero);
    }
}

Diferencias con los errores de compilación

Los errores en tiempo de ejecución presentan diferencias fundamentales con los errores de compilación:

| Aspecto | Errores de compilación | Errores en tiempo de ejecución | |---------|----------------------|-------------------------------| | Momento de detección | Antes de la ejecución | Durante la ejecución | | Prevención | Compilador los detecta | Requieren pruebas exhaustivas | | Impacto | Impiden la ejecución | Pueden terminar el programa |

Situaciones comunes que causan errores en tiempo de ejecución

  • 1. Entrada de datos incorrecta

Cuando el usuario proporciona datos que no coinciden con lo esperado:

import java.util.Scanner;

public class EjemploEntrada {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.print("Introduce un número: ");
        
        // Si el usuario introduce "hola", se lanza NumberFormatException
        int numero = Integer.parseInt(scanner.nextLine());
        System.out.println("El número es: " + numero);
    }
}
  • 2. Operaciones con objetos no inicializados

Trabajar con referencias que no han sido inicializadas correctamente:

public class EjemploInicializacion {
    public static void main(String[] args) {
        String[] palabras = new String[3];
        // El array se crea pero sus elementos son null
        System.out.println(palabras[0].toUpperCase()); // NullPointerException
    }
}
  • 3. Acceso a recursos externos

Problemas con archivos, conexiones de red o bases de datos:

import java.io.FileReader;
import java.io.IOException;

public class EjemploRecursos {
    public static void main(String[] args) {
        // Si el archivo no existe, se lanza FileNotFoundException
        FileReader archivo = new FileReader("archivo_inexistente.txt");
    }
}

Información de depuración en errores en tiempo de ejecución

Cuando ocurre un error en tiempo de ejecución, Java proporciona un stack trace que muestra la secuencia de llamadas a métodos que llevaron al error:

Exception in thread "main" java.lang.NullPointerException
    at EjemploError.procesarTexto(EjemploError.java:12)
    at EjemploError.main(EjemploError.java:6)

Este rastro de la pila incluye:

  • El tipo de excepción (NullPointerException)
  • La clase y método donde ocurrió (EjemploError.procesarTexto)
  • El número de línea exacto (línea 12)
  • La secuencia completa de llamadas

Prevención de errores en tiempo de ejecución

  • 1. Validación de datos de entrada

Verificar que los datos cumplan con los requisitos esperados antes de procesarlos:

public class ValidacionEntrada {
    public static void main(String[] args) {
        String input = "123abc"; // Entrada problemática
        
        // Verificar si la cadena contiene solo números
        if (input.matches("\\d+")) {
            int numero = Integer.parseInt(input);
            System.out.println("Número válido: " + numero);
        } else {
            System.out.println("Entrada inválida: " + input);
        }
    }
}
  • 2. Verificación de referencias nulas

Comprobar que las referencias no sean null antes de utilizarlas:

public class VerificacionNulos {
    public static void main(String[] args) {
        String texto = obtenerTexto(); // Puede devolver null
        
        if (texto != null) {
            System.out.println("Longitud: " + texto.length());
        } else {
            System.out.println("El texto es nulo");
        }
    }
    
    public static String obtenerTexto() {
        // Simulación de método que puede devolver null
        return Math.random() > 0.5 ? "Hola mundo" : null;
    }
}
  • 3. Validación de índices de arrays

Asegurar que los índices estén dentro del rango válido del array:

public class ValidacionIndices {
    public static void main(String[] args) {
        int[] numeros = {10, 20, 30};
        int indice = 5; // Índice problemático
        
        if (indice >= 0 && indice < numeros.length) {
            System.out.println("Valor: " + numeros[indice]);
        } else {
            System.out.println("Índice fuera de rango: " + indice);
        }
    }
}

Los errores en tiempo de ejecución requieren un enfoque proactivo en el diseño del código. Mediante validaciones apropiadas y pruebas exhaustivas, se pueden minimizar significativamente estos errores, creando aplicaciones más robustas y confiables.

Uso básico de try-catch

El mecanismo try-catch es la herramienta fundamental en Java para gestionar errores en tiempo de ejecución de forma controlada. En lugar de permitir que las excepciones terminen abruptamente el programa, este mecanismo nos permite capturar y manejar los errores, manteniendo la estabilidad de la aplicación.

Concepto y propósito del try-catch

La estructura try-catch funciona bajo el principio de "intentar y capturar". El bloque try contiene el código que puede generar una excepción, mientras que el bloque catch define cómo responder cuando esa excepción ocurre. Esta aproximación permite que el programa continúe ejecutándose incluso después de encontrar un error.

El control de flujo cambia cuando se produce una excepción: la ejecución salta inmediatamente del punto donde ocurre el error al bloque catch correspondiente, omitiendo cualquier código restante en el bloque try.

Sintaxis básica del try-catch

La estructura más simple de try-catch sigue este patrón:

try {
    // Código que puede lanzar una excepción
} catch (TipoDeExcepcion e) {
    // Código para manejar la excepción
}

Un ejemplo práctico que maneja una división entre cero:

public class EjemploBasico {
    public static void main(String[] args) {
        int dividendo = 10;
        int divisor = 0;
        
        try {
            int resultado = dividendo / divisor;
            System.out.println("Resultado: " + resultado);
        } catch (ArithmeticException e) {
            System.out.println("Error: No se puede dividir entre cero");
        }
        
        System.out.println("El programa continúa ejecutándose");
    }
}

Captura de excepciones específicas

Java permite capturar tipos específicos de excepciones, lo que facilita proporcionar respuestas apropiadas para cada tipo de error:

import java.util.Scanner;

public class EjemploEspecifico {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int[] numeros = {10, 20, 30};
        
        System.out.print("Introduce un índice: ");
        
        try {
            String entrada = scanner.nextLine();
            int indice = Integer.parseInt(entrada);
            System.out.println("Valor en posición " + indice + ": " + numeros[indice]);
        } catch (NumberFormatException e) {
            System.out.println("Error: Debes introducir un número válido");
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("Error: El índice está fuera del rango del array");
        }
    }
}

Múltiples bloques catch

Un bloque try puede tener varios bloques catch para manejar diferentes tipos de excepciones. Java evalúa los bloques catch en orden, ejecutando el primero que coincida con el tipo de excepción:

public class EjemploMultiple {
    public static void main(String[] args) {
        String[] datos = {"100", "50", "abc", "25"};
        
        for (String dato : datos) {
            try {
                int numero = Integer.parseInt(dato);
                int resultado = 1000 / numero;
                System.out.println("Resultado para " + dato + ": " + resultado);
            } catch (NumberFormatException e) {
                System.out.println("'" + dato + "' no es un número válido");
            } catch (ArithmeticException e) {
                System.out.println("No se puede dividir entre cero: " + dato);
            }
        }
    }
}

Captura genérica con Exception

Cuando queremos capturar cualquier tipo de excepción, podemos usar la clase base Exception:

public class EjemploGenerico {
    public static void main(String[] args) {
        String texto = null;
        
        try {
            System.out.println("Longitud del texto: " + texto.length());
            int numero = Integer.parseInt("abc");
        } catch (Exception e) {
            System.out.println("Ha ocurrido un error: " + e.getMessage());
        }
    }
}

El bloque finally

El bloque finally se ejecuta siempre, independientemente de si ocurre una excepción o no. Es útil para tareas de limpieza como cerrar archivos o liberar recursos:

public class EjemploFinally {
    public static void main(String[] args) {
        try {
            int resultado = 10 / 2;
            System.out.println("Resultado: " + resultado);
        } catch (ArithmeticException e) {
            System.out.println("Error aritmético");
        } finally {
            System.out.println("Este bloque siempre se ejecuta");
        }
    }
}

Información de la excepción

El objeto de excepción capturado contiene información útil sobre el error que podemos utilizar:

public class EjemploInformacion {
    public static void main(String[] args) {
        try {
            String texto = "abc";
            int numero = Integer.parseInt(texto);
        } catch (NumberFormatException e) {
            System.out.println("Tipo de error: " + e.getClass().getSimpleName());
            System.out.println("Mensaje: " + e.getMessage());
            System.out.println("Descripción completa: " + e.toString());
        }
    }
}

Manejo de errores de entrada de usuario

Un caso práctico común es validar la entrada del usuario utilizando try-catch:

import java.util.Scanner;

public class ValidacionEntrada {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        boolean entradaValida = false;
        int edad = 0;
        
        while (!entradaValida) {
            System.out.print("Introduce tu edad: ");
            try {
                edad = Integer.parseInt(scanner.nextLine());
                if (edad >= 0 && edad <= 150) {
                    entradaValida = true;
                } else {
                    System.out.println("La edad debe estar entre 0 y 150 años");
                }
            } catch (NumberFormatException e) {
                System.out.println("Por favor, introduce un número válido");
            }
        }
        
        System.out.println("Edad registrada: " + edad + " años");
    }
}

Buenas prácticas básicas

  • 1. Ser específico en las excepciones

Capturar tipos específicos de excepciones en lugar de usar Exception genérica permite un manejo más preciso:

// Preferible
try {
    int numero = Integer.parseInt(entrada);
} catch (NumberFormatException e) {
    System.out.println("Formato numérico incorrecto");
}

// Menos recomendado
try {
    int numero = Integer.parseInt(entrada);
} catch (Exception e) {
    System.out.println("Error general");
}
  • 2. No ignorar las excepciones

Evitar bloques catch vacíos que ocultan errores importantes:

// Incorrecto - ignora el error
try {
    int resultado = rieskyOperation();
} catch (Exception e) {
    // Bloque vacío - error ignorado
}

// Correcto - maneja el error apropiadamente
try {
    int resultado = rieskyOperation();
} catch (Exception e) {
    System.out.println("Error en operación: " + e.getMessage());
}
  • 3. Mantener la lógica de negocio separada

El manejo de errores no debe interferir con la lógica principal del programa:

public class CalculadoraSegura {
    public static void main(String[] args) {
        double resultado = dividir(10, 0);
        System.out.println("Resultado de la división: " + resultado);
    }
    
    public static double dividir(double a, double b) {
        try {
            return a / b;
        } catch (ArithmeticException e) {
            System.out.println("División entre cero detectada");
            return 0; // Valor por defecto
        }
    }
}

El uso efectivo de try-catch transforma los errores en tiempo de ejecución de interrupciones abruptas en oportunidades para proporcionar respuestas apropiadas. Este mecanismo es esencial para crear aplicaciones robustas que puedan manejar situaciones imprevistas de manera elegante y mantener una experiencia de usuario positiva.

Fuentes y referencias

Documentación oficial y recursos externos para profundizar en Java

Documentación oficial de Java
Alan Sastre - Autor del tutorial

Alan Sastre

Ingeniero de Software y formador, CEO en CertiDevs

Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Java es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.

Más tutoriales de Java

Explora más contenido relacionado con Java y continúa aprendiendo con nuestros tutoriales gratuitos.

Aprendizajes de esta lección

  • Comprender qué son y cómo se detectan los errores de compilación en Java.
  • Identificar los principales tipos de errores en tiempo de ejecución y sus causas comunes.
  • Aprender a interpretar mensajes de error y stack traces para facilitar la depuración.
  • Utilizar la estructura try-catch para capturar y manejar excepciones de forma controlada.
  • Aplicar buenas prácticas básicas en el manejo de excepciones para mejorar la robustez del código.