Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

0x3 - Manejo de Excepciones

Universidad Nacional de Rio Negro - Sede Andina

Serie 0x3 - Manejo de Excepciones

0x3000 - No atajar la excepción si no es posible tomar una decisión

Explicación

Si solo vas a loggear o relanzar sin agregar valor, dejá que la excepción se propague naturalmente.

Incorrecto ❌:

try {
    procesarArchivo();
} catch (IOException e) {
    // Solo loggear y relanzar
    logger.error("Error: " + e.getMessage());
    throw e;  // ❌ No agrega valor
}

Correcto ✅:

// ✅ Dejar propagar - agregar throws en firma
public void procesar() throws IOException {
    procesarArchivo();  // Propaga naturalmente
}

0x3001 - El main de un programa no debe dejar pasar excepciones checked

Explicación

El main debe manejar todas las excepciones checked y proporcionar mensajes de error apropiados al usuario final.

Incorrecto ❌:

public static void main(String[] args) throws Exception {  // ❌
    // código
}

Correcto ✅:

public static void main(String[] args) {
    try {
        ejecutarPrograma();
    } catch (IOException e) {
        System.err.println("Error de archivo: " + e.getMessage());
        System.exit(1);
    }
}

0x3002 - Qué familia de excepciones se eligió debe estar documentada

Explicación

Documentar en el paquete o clase base por qué se usa checked vs unchecked para las excepciones del dominio.

/**
 * Excepciones del dominio de Facturación.
 * <p>
 * Se usan excepciones UNCHECKED porque:
 * - Los errores son de programación (precondiciones violadas)
 * - No se espera recuperación en tiempo de ejecución
 */
package ar.unrn.facturacion.excepciones;

0x3003 - No atajar una excepción lanzada en el mismo bloque

Explicación

Si lanzás una excepción dentro de un try y la atajás en el mismo catch, usá if-else en su lugar.

Incorrecto ❌:

try {
    if (invalido) {
        throw new IllegalArgumentException();
    }
} catch (IllegalArgumentException e) {
    // manejar
}

Correcto ✅:

if (invalido) {
    // manejar directamente
} else {
    // flujo normal
}

0x3004 - No convertir excepciones checked a unchecked sin justificación

Explicación

No atajar una excepción checked (IOException, SQLException) y relanzar una excepción unchecked genérica perdiendo información del tipo original.

Incorrecto ❌:

try {
    leerArchivo();
} catch (IOException e) {
    throw new RuntimeException("Error");  // ❌ Pérdida de información
}

Correcto ✅:

try {
    leerArchivo();
} catch (IOException e) {
    throw new ArchivoNoDisponibleException("No se pudo leer: " + archivo, e);
}

0x3005 - Sean específicos con lo que atajan, no está permitido atajar Exception o RuntimeException

Explicación

Atajar excepciones específicas, no genéricas. Esto permite manejar cada caso apropiadamente.

Incorrecto ❌:

try {
    // código
} catch (Exception e) {  // ❌ Demasiado genérico
    // manejar
}

Correcto ✅:

try {
    // código
} catch (IOException e) {
    // manejar IO
} catch (SQLException e) {
    // manejar BD
}

0x3006 - Situaciones diferentes requieren excepciones diferentes

Explicación

Situaciones como “arreglo vacío” y “arreglo null” son casos diferentes que ameritan mensajes y tipos de excepciones distintos.

Incorrecto ❌:

if (arreglo == null || arreglo.length == 0) {
    throw new IllegalArgumentException("Arreglo inválido");
}

Correcto ✅:

if (arreglo == null) {
    throw new NullPointerException("El arreglo no puede ser null");
}
if (arreglo.length == 0) {
    throw new IllegalArgumentException("El arreglo no puede estar vacío");
}

Ejemplo reutilizable (TP3 - Arreglos):

/**
 * Verifica que un arreglo no sea null ni esté vacío.
 * @param arreglo el arreglo a verificar
 * @throws NullPointerException si el arreglo es null
 * @throws IllegalArgumentException si el arreglo está vacío
 */
private static void validarArreglo(int[] arreglo) {
    if (arreglo == null) {
        throw new NullPointerException("El arreglo no puede ser null");
    }
    if (arreglo.length == 0) {
        throw new IllegalArgumentException("El arreglo no puede estar vacío");
    }
}

0x3007 - ‘Largo cero’ y null son dos situaciones bastante diferentes

Explicación

Que requieren de excepciones distintas para que su tratamiento pueda ser más específico. Ver 0x3006 - Situaciones diferentes requieren excepciones diferentes.

0x3008 - Declarar el lanzamiento de una excepción no controlada es un error

Explicación

No es correcto (ni necesario) declarar throws para RuntimeException y sus subclases.

Incorrecto ❌:

public void metodo() throws RuntimeException {  // ❌ Innecesario
    // código
}

Correcto ✅:

public void metodo() {  // ✅ RuntimeException no se declara
    // código
}

0x3009 - No está permitido lanzar excepciones base: Exception o RuntimeException

Explicación

Lanzar excepciones específicas del dominio o estándar de Java, no las clases base.

Incorrecto ❌:

throw new Exception("error");
throw new RuntimeException("error");

Correcto ✅:

throw new MiExcepcionEspecifica("error");
throw new IllegalArgumentException("parámetro inválido");

0x300A - Mejor prevenir que atajar

Explicación

Siempre que sea posible, prevenir la excepción en lugar de esperar a que falle (LBYL - Look Before You Leap).

Menos óptimo ⚠️:

try {
    int resultado = dividir(a, b);
} catch (ArithmeticException e) {
    // manejar división por cero
}

Mejor ✅:

if (b != 0) {
    int resultado = dividir(a, b);
} else {
    // manejar caso especial
}

0x300B - Silenciar una excepción no es la forma de gestionarla

Explicación

No dejar bloques catch vacíos. Como mínimo, loggear el error.

Incorrecto ❌:

try {
    operacionRiesgosa();
} catch (Exception e) {
    // ❌ Bloque vacío - se silencia el error
}

Correcto ✅:

try {
    operacionRiesgosa();
} catch (Exception e) {
    logger.error("Error en operación riesgosa", e);
    // Y tomar decisión: reintentar, valor por defecto, etc.
}

0x300C - No está permitido atajar para relanzar sin agregar información útil

Explicación

Si solo envolvés la excepción sin agregar contexto, dejá que se propague.

Incorrecto ❌:

try {
    leerArchivo();
} catch (IOException e) {
    throw new IOException(e);  // ❌ Solo envuelve, no agrega valor
}

Correcto ✅:

try {
    leerArchivo();
} catch (IOException e) {
    throw new ArchivoConfiguracionException(
        "No se pudo leer configuración de: " + archivo, e);
}

0x300D - Atajar para hacer algún tipo de print no es gestionar la excepción

Explicación

Imprimir el stack trace no es manejar la excepción. Usar logging apropiado y tomar decisión sobre cómo continuar.

Incorrecto ❌:

try {
    operacion();
} catch (Exception e) {
    e.printStackTrace();  // ❌ Solo imprime, no maneja
}

Correcto ✅:

try {
    operacion();
} catch (OperacionException e) {
    logger.error("Error en operación", e);
    // Reintentar, usar valor por defecto, o relanzar
}