Excepciones y archivos en Java

Aprende cómo Java informa de los problemas mientras se ejecuta un programa y cómo resolverlos. Interpreta trazas de la pila, distingue las excepciones comprobadas de las no comprobadas y maneja errores con try, catch y finally. Lanza tus propias excepciones y diseña clases de excepciones que indiquen exactamente qué salió mal. Después, lee y escribe archivos de texto controlando las rutas, las codificaciones y los fines de línea, cierra cada archivo de forma segura con try-with-resources y crea un programa que gestione archivos inexistentes y datos incorrectos.

PrincipianteUnidad 9 de 11 del curso Curso de Programación orientada a objetos con Java

Lo que aprenderás

  1. Reconoce una excepción cuando falla un programa, interpreta la traza de la pila para encontrar dónde y por qué ocurrió, y sitúa cualquier excepción en la jerarquía de clases de Java como comprobada o no comprobada.
    • Interpreta una excepción y su traza de la pila
      Explica qué sucede cuando una sentencia lanza una excepción, nombra las excepciones habituales en tiempo de ejecución y sus causas, y utiliza una traza de la pila para localizar el problema.
    • Clasifica las excepciones en comprobadas y no comprobadas
      Sitúa cualquier excepción en la jerarquía por debajo de Throwable, determina si es comprobada o no comprobada y aplica la regla de que las excepciones comprobadas deben capturarse o declararse.
  2. Captura las excepciones que un programa puede prever, recupérate de ellas de forma razonable, maneja varios tipos en el orden adecuado y ejecuta código de limpieza pase lo que pase.
    • Captura una excepción y recupera la ejecución
      Escribe una sentencia try-catch, sigue cómo pasa el control por ella y recupérate de una entrada incorrecta en vez de dejar que el programa falle.
    • Maneja varios tipos de excepciones en el orden adecuado
      Usa varias cláusulas catch o una captura múltiple, ordénalas de la más específica a la más general y decide dónde debe empezar y terminar un bloque try.
    • Ejecuta código de limpieza con finally
      Añade un bloque finally, sigue cuándo se ejecuta en cada ruta de una sentencia try y evita los errores que hacen que finally oculte problemas.
  3. Señala problemas desde tus propios métodos con throw, declara excepciones comprobadas con throws y crea clases de excepciones que indiquen a quienes llaman exactamente qué salió mal.
    • Lanza excepciones y decláralas con throws
      Valida argumentos y el estado de los objetos lanzando excepciones estándar, declara excepciones comprobadas en cabeceras de métodos y decide dónde debe manejarse una excepción.
    • Crea clases de excepciones personalizadas y conserva la causa
      Escribe tus propias clases de excepciones comprobadas o no comprobadas, lánzalas antes de cambiar el estado de un objeto y envuelve una excepción de bajo nivel sin perderla.
  4. Indica a un programa dónde está el archivo correcto, comprende cómo se almacena el texto en bytes y líneas, y asegúrate de cerrar cada archivo abierto con try-with-resources.
    • Trabaja con rutas, codificaciones y fines de línea
      Construye rutas a archivos, predice dónde busca Java una ruta relativa y explica cómo afectan las codificaciones de caracteres, los fines de línea y los formatos numéricos a los archivos de texto.
    • Cierra recursos automáticamente con try-with-resources
      Usa try-with-resources para abrir y cerrar archivos y otros recursos, predice el orden de cierre y explica cómo evita que se pierdan excepciones.
  5. Lee archivos de texto línea por línea y convierte sus líneas en datos, escribe resultados en archivos o añádelos al final, y combina todo en un programa que gestione archivos inexistentes y registros incorrectos.
    • Lee un archivo de texto y convierte sus líneas en datos
      Lee un archivo con Scanner, Files.readAllLines o BufferedReader, divide y convierte cada línea, y omite o notifica las líneas que no se ajustan al formato esperado.
    • Escribe archivos de texto y añade contenido al final
      Escribe texto en un archivo nuevo o existente, añade contenido al final sin borrar lo que hay y asegúrate de que todo lo escrito llegue realmente al archivo.
    • Crea un programa robusto de procesamiento de archivos
      Combina lectura, análisis, excepciones y escritura en un programa que se detenga correctamente ante fallos del archivo completo, omita y notifique registros incorrectos y evite una salida parcial.

Guía de estudio de Excepciones y archivos en Java

5 capítulos

1

Comprende qué son las excepciones y cómo las clasifica Java

Un programa puede compilarse correctamente y aun así fallar cuando recibe un arreglo vacío, texto no válido o un archivo inexistente. El objeto de excepción y su traza de la pila te dan información sobre ese fallo. Sigue la traza hacia atrás por las llamadas a métodos activas y después usa la jerarquía de clases para decidir si Java exige una decisión de manejo en tiempo de compilación. Esto te prepara para distinguir los fallos que debes corregir de los problemas esperados de los que tu programa puede recuperarse.

1.1 Encuentra la sentencia que falla

Una excepción es un objeto que describe un problema que interrumpe un programa en ejecución. Lanzarla detiene la sentencia actual. Java omite el trabajo normal restante hasta encontrar un manejador de excepciones que coincida; si no lo hay, la excepción se propaga hacia atrás por los métodos que llamaron.

Reconoce el tipo de problema

La falta de un punto y coma es un error en tiempo de compilación: el programa no puede compilarse. Una excepción ocurre cuando el código compilado se ejecuta con datos que provocan un problema.

ExcepciónCausa habitual
ArithmeticExceptionDivisión entera entre cero
ArrayIndexOutOfBoundsExceptiona[3] cuando el arreglo tiene longitud 3
IndexOutOfBoundsExceptionlist.get(list.size())
NullPointerExceptionLlamar a un método mediante null
NumberFormatExceptionInteger.parseInt("12a")
InputMismatchExceptionScanner.nextInt() encuentra «ten»
ClassCastExceptionConvertir un objeto a una clase a la que no pertenece

Los índices de los arreglos empiezan en 0, por lo que una longitud de 3 significa que los índices válidos son 0, 1 y 2. La división en coma flotante sigue reglas diferentes: 10.0 / 0 produce Infinity; no lanza la excepción de la división entera.

Lee una traza desde arriba

Aquí tienes una clase completa, sin líneas en blanco antes de la primera línea:

public class Average {
    static int average(int[] values) {
        int sum = 0;
        for (int value : values) sum += value;
        return sum / values.length;
    }
    public static void main(String[] args) {
        int[] values = new int[0];
        System.out.println(average(values));
    }
}

El arreglo está vacío, por lo que su longitud es 0. La división de la línea 5 falla. La traza es:

Exception in thread "main" java.lang.ArithmeticException: / by zero
    at Average.average(Average.java:5)
    at Average.main(Average.java:9)
  1. Lee la primera línea para conocer la clase de excepción y el mensaje.
  2. Lee el primer marco at para localizar dónde se detectó el problema.
  3. Lee hacia abajo para identificar a quienes llamaron: main llamó a average en la línea 9.
  4. Si los primeros marcos pertenecen a la biblioteca de Java, busca el primero que nombre una clase tuya. Si falla Integer.parseInt, pueden aparecer marcos de la biblioteca antes de la llamada en tu código.

La traza sigue la pila de llamadas, la cadena de llamadas a métodos activas. Te indica dónde investigar, pero el valor incorrecto puede haberse creado antes. Aquí la división detecta el problema; quien llamó proporcionó el arreglo vacío. Decide si debe rechazarse o manejarse una entrada vacía antes de calcular una media.

Inspecciona el objeto de excepción

e.getMessage() devuelve el mensaje y puede devolver null. e.toString() incluye el nombre de la clase y, cuando existe, el mensaje. e.printStackTrace() imprime la traza en el error estándar. Una sección Caused by: muestra una excepción anterior conservada dentro de una excepción envoltorio.

Los mensajes de NullPointerException generados por la JVM suelen identificar la expresión nula. En cambio, una excepción creada explícitamente puede tener un mensaje personalizado o ninguno. Sigue la referencia hasta donde debería haber recibido un objeto.

Una excepción sin manejar que sale de main termina el hilo principal; eso termina un programa de un solo hilo. Corrige en el código los fallos, como los índices incorrectos. Planifica la recuperación ante problemas externos esperados, como un archivo inexistente o una entrada de usuario no válida.

Puntos clave

  • Una excepción interrumpe la ejecución normal; las sentencias omitidas no se reanudan automáticamente.
  • Lee la clase de excepción y el mensaje, y sigue los marcos de pila desde el fallo detectado hasta quienes llamaron.
  • Pueden aparecer marcos de la biblioteca antes del primer marco de tu propio código.
  • La sentencia que falla puede revelar un valor incorrecto creado antes.
  • Corrige los fallos de programación y maneja los fallos esperados de entrada o de archivos.

1.2 Excepciones comprobadas y no comprobadas

Las clases de excepciones usan las reglas de herencia que ya conoces. Un objeto de una subclase que se lanza también pertenece a su superclase, lo que explica tanto las categorías de excepciones de Java como la forma en que un manejador las reconoce.

Sigue la jerarquía

Solo pueden lanzarse objetos de Throwable o de sus subclases. Por debajo hay dos ramas principales:

Throwable
  Error
    OutOfMemoryError
    StackOverflowError
  Exception
    RuntimeException
      IllegalArgumentException
        NumberFormatException
      NullPointerException
      IndexOutOfBoundsException
        ArrayIndexOutOfBoundsException
    IOException
      FileNotFoundException
      NoSuchFileException

Error describe fallos graves del entorno de ejecución. Una aplicación normal no debería intentar recuperarse de una memoria dinámica agotada o de una pila agotada por una recursión interminable. Exception describe problemas que una aplicación puede manejar, incluida su rama RuntimeException.

CategoríaClasesExigencia del compilador
No comprobadasRuntimeException, Error y sus subclasesCapturar o declarar es opcional
ComprobadasTodas las demás subclases de ThrowableCapturar o declarar cuando el código pueda lanzarlas

Ambos tipos se lanzan en tiempo de ejecución. La palabra «comprobada» describe la comprobación del manejo por el compilador, no un momento anterior en el que ocurre el fallo. No comprobada tampoco significa inofensiva: una referencia nula sin manejar puede detener un programa.

Aplica la regla de capturar o declarar

La lectura de un archivo puede fallar incluso con código correcto. Un método auxiliar puede dejar la decisión a quien lo llama:

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

class Names {
    static List<String> load(Path file) throws IOException {
        return Files.readAllLines(file);
    }
}

Files.readAllLines puede lanzar la excepción comprobada IOException. La declaración pasa esa posibilidad a quien llama, que también debe capturarla o declararla. Si se elimina throws IOException sin añadir un manejador, el método auxiliar no compila. Un método que usa Integer.parseInt no tiene una obligación equivalente del compilador porque NumberFormatException es no comprobada.

Los fallos comprobados suelen describir condiciones que quien llama puede prever, como la desaparición de un archivo. Los fallos en tiempo de ejecución suelen identificar errores o argumentos no válidos. Son razones de diseño útiles, pero la cadena de superclases determina la categoría. Una clase personalizada que extiende RuntimeException sigue siendo no comprobada aunque quien llama pueda recuperarse.

Relaciona los manejadores mediante la herencia

catch (IOException e) puede manejar una FileNotFoundException o una NoSuchFileException. catch (Exception e) también captura excepciones en tiempo de ejecución; puede convertir un fallo de código en un mensaje de entrada engañoso. catch (Throwable e) también alcanza la rama Error y rara vez es apropiado para la recuperación normal.

Para clasificar una clase desconocida, sigue su herencia hacia arriba en la documentación de la API. InputMismatchException extiende NoSuchElementException, que extiende RuntimeException, por lo que es no comprobada. InterruptedException extiende Exception fuera de la rama de ejecución, por lo que es comprobada. Se permite declarar un tipo no comprobado en una cláusula throws, pero eso no cambia su categoría.

Puntos clave

  • RuntimeException, Error y todas sus subclases son no comprobadas.
  • Las demás subclases de Throwable son comprobadas; el código que puede lanzarlas debe capturarlas o declararlas.
  • Tanto las excepciones comprobadas como las no comprobadas ocurren en tiempo de ejecución.
  • Un catch para una superclase también coincide con sus subclases.
  • Un manejador general de Exception puede ocultar fallos de programación.
  • Clasifica una excepción desconocida por su cadena de superclases.
2

Maneja excepciones con try, catch y finally

Manejar un fallo cambia qué sentencias se ejecutan a continuación. Un manejador útil debe coincidir con la excepción y dejar el programa listo para continuar, mientras que la limpieza también debe ejecutarse en las rutas que salen antes de tiempo. Sigue las conversiones y los bucles paso a paso, elige los manejadores específicos antes que los generales y coloca el bloque protegido alrededor del trabajo que debe fallar en conjunto. Después, sigue cómo se comporta finally cuando se propaga una excepción o un método retorna.

2.1 Recupérate de una conversión fallida

Un bloque try marca el trabajo que puede fallar. Un bloque catch que coincida proporciona al programa una acción útil a continuación, como pedir otro valor. Manejar la excepción no reintenta por sí solo la sentencia que falló.

Sigue las ramas
System.out.println("A");
try {
    System.out.println("B");
    int value = Integer.parseInt("4x");
    System.out.println("C");
} catch (NumberFormatException e) {
    System.out.println("D: " + e.getMessage());
}
System.out.println("E");

La salida es A, B, D: For input string: "4x" y E, cada uno en su propia línea. La conversión falla, por lo que Java omite C y entra en el manejador correspondiente. Cuando ese manejador termina normalmente, la ejecución continúa después de toda la sentencia. Si la conversión tiene éxito, se omite el manejador. Si el bloque lanza una ArithmeticException, este manejador no coincide y la excepción se propaga.

Reintenta con una entrada nueva

Lee una línea completa antes de convertirla. El siguiente bucle acepta un número entero y maneja el final de la entrada del teclado informando de que no se proporcionó ningún valor:

import java.util.Scanner;

class WholeNumbers {
    static int readWholeNumber(Scanner in) {
        while (in.hasNextLine()) {
            String line = in.nextLine();
            try {
                return Integer.parseInt(line.trim());
            } catch (NumberFormatException e) {
                System.out.println("Please enter a whole number.");
            }
        }
        throw new IllegalStateException("No number supplied");
    }
}

Para las entradas «twenty» y «20», el manejador imprime una vez, el bucle lee una línea nueva y el método devuelve 20. trim() elimina los caracteres de espacio en blanco que rodean el texto: de otro modo, Integer.parseInt(" 20") falla. La conversión acepta un signo opcional y dígitos que representen un entero dentro del rango permitido.

Un scanner basado en unidades de entrada necesita otra solución. Cuando nextInt() encuentra «ten», su InputMismatchException deja esa unidad sin leer. Capturarla y volver a llamar a nextInt() repite el fallo indefinidamente. Consume la unidad incorrecta con next() o descarta la línea con nextLine() antes de reintentar. hasNextInt() puede comprobar una unidad antes de la conversión.

Mantén utilizable el estado recuperado

Una variable declarada dentro de try solo existe en ese bloque. Si el código posterior necesita el resultado, declárala fuera y haz que cada ruta que continúe le asigne un valor válido:

int quantity;
try {
    quantity = Integer.parseInt("bad");
} catch (NumberFormatException e) {
    quantity = 0;
}
System.out.println(quantity);

Cero solo es apropiado aquí si el programa lo define como un valor alternativo válido. Dejar quantity sin asignar en el manejador provoca un error de asignación definida en tiempo de compilación.

Captura el tipo específico que puedes manejar. Un manejador vacío pierde el problema sin avisar; un catch (Exception e) general puede etiquetar un fallo de referencia nula como un número incorrecto. La recuperación debe volver a preguntar, omitir un elemento, elegir un valor predeterminado válido, informar del fallo o propagar una excepción significativa. Para límites sencillos y previsibles, comprueba primero: index >= 0 && index < list.size() evita índices de lista tanto negativos como demasiado grandes.

Puntos clave

  • Un manejador que coincide se ejecuta después de omitir el resto del bloque try que falló.
  • Un bucle debe leer una entrada nueva antes de volver a intentarlo.
  • Scanner.nextInt() deja sin leer una unidad de entrada que no coincide.
  • Toda ruta que continúe debe dejar las variables usadas después inicializadas con valores razonables.

2.2 Elige los manejadores y el trabajo que protegen

Un archivo puede no existir, no poder leerse o estar lleno de registros mal formados. Esos fallos necesitan respuestas diferentes. Varios manejadores permiten que un try los distinga, mientras que la posición del bloque determina cuánto trabajo se detiene cuando algo falla.

Coloca primero los manejadores específicos

Java comprueba los manejadores de arriba abajo y ejecuta el primero que coincide. No sigue ejecutando manejadores posteriores para la misma excepción.

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;

class FirstCount {
    static void show(Path file) {
        try {
            int count = Integer.parseInt(Files.readString(file).trim());
            System.out.println(count);
        } catch (NoSuchFileException e) {
            System.out.println("File not found: " + file.toAbsolutePath());
        } catch (IOException e) {
            System.out.println("Could not read: " + file.toAbsolutePath());
        } catch (NumberFormatException e) {
            System.out.println("The file must contain one whole number.");
        }
    }
}

NoSuchFileException extiende IOException, por lo que debe ir primero. Invertirlas hace que el manejador específico sea inalcanzable e impide la compilación. La excepción de conversión no está relacionada con IOException, por lo que esos dos manejadores pueden aparecer en cualquier orden.

Un manejador de una excepción comprobada también debe ser pertinente para el trabajo protegido. Se rechaza capturar IOException alrededor de solo int count = 5; porque ese bloque no puede lanzarla. Esta restricción no se aplica de la misma forma a los tipos no comprobados ni a los tipos generales Exception y Throwable.

Comparte un manejador cuando la respuesta sea la misma

Una captura múltiple une tipos de excepciones no relacionados con |:

try {
    String[] parts = "Ana".split(",");
    int age = Integer.parseInt(parts[1]);
    System.out.println(age);
} catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
    System.out.println("Invalid record: " + e.getMessage());
}

Aquí la ausencia del segundo campo provoca la excepción de índice. Un campo presente pero no numérico provocaría la excepción de conversión, y ambos reciben la misma respuesta. El parámetro de la captura múltiple es implícitamente final. Las alternativas no pueden ser una subclase y su superclase: FileNotFoundException | IOException no es válido porque IOException ya cubre ambas.

Decide qué debe omitir un fallo

Considera los textos «3», «x» y «5». Con un try alrededor de todo el bucle, el procesamiento se detiene en «x» y la suma hasta ese momento es 3. Coloca el try dentro del bucle para recuperarte por separado de cada elemento:

int sum = 0;
for (String text : new String[] {"3", "x", "5"}) {
    try {
        sum += Integer.parseInt(text);
    } catch (NumberFormatException e) {
        System.out.println("Skipped: " + text);
    }
}
System.out.println(sum);

Esto imprime Skipped: x y después 8. El bucle continúa porque su cuerpo manejó el fallo de ese registro. Los manejadores anidados buscan hacia fuera desde el bloque protegido más interno; un manejador interno que no coincide da una oportunidad a uno externo. Elige la unidad de trabajo más pequeña que deba fallar en conjunto: un registro para datos incorrectos, la operación de archivo para un fallo de lectura.

Puntos clave

  • Java ejecuta como máximo un manejador que coincida por cada excepción.
  • Captura una subclase antes que su superclase.
  • La captura múltiple comparte una respuesta entre tipos de excepciones no relacionados.
  • La captura múltiple no puede combinar una superclase con su subclase.
  • Coloca la recuperación de cada registro dentro del bucle para continuar con los registros posteriores.

2.3 Ejecuta la limpieza antes de que salga el control

Parte del trabajo debe realizarse tanto si una operación tiene éxito como si falla. Un bloque finally se ejecuta cuando el control sale de su sentencia try, incluso cuando se propaga una excepción o un método retorna.

Sigue una excepción que no coincide
try {
    System.out.println("1");
    int[] values = new int[2];
    values[2] = 7;
    System.out.println("2");
} catch (NumberFormatException e) {
    System.out.println("3");
} finally {
    System.out.println("4");
}
System.out.println("5");

Solo se imprimen 1 y 4 antes de que se propague la ArrayIndexOutOfBoundsException. El índice 2 está fuera del arreglo de dos elementos. El manejador no coincide, pero finally se ejecuta igualmente. La sentencia que imprime 5 está fuera del bloque de limpieza, por lo que la excepción que se propaga la omite.

Si el trabajo protegido lanza en cambio una NumberFormatException que coincide después de imprimir 1, el manejador imprime 3, la limpieza imprime 4 y la ejecución continúa hasta 5. En una ruta satisfactoria no se ejecuta ningún manejador, pero la limpieza sí.

Los valores de retorno se preparan antes de la limpieza
class Cleanup {
    static int result() {
        try {
            return 1;
        } finally {
            System.out.println("cleanup");
        }
    }
}

La expresión de retorno se evalúa primero. Después Java imprime cleanup y quien llamó recibe 1. Un break o continue que sale de una región protegida también ejecuta su limpieza antes de que surta efecto la transferencia de control.

Mantén return fuera de finally. Un return 2; allí sustituiría el valor de retorno pendiente y podría incluso descartar una excepción pendiente. Una excepción lanzada por la limpieza también puede sustituir el fallo original. La limpieza no debería introducir un segundo resultado que entre en conflicto. La opción -Xlint:finally del compilador advierte cuando un bloque finally no puede terminar normalmente.

Cierra un objeto solo si se abrió

El patrón manual más antiguo necesita una variable visible para el bloque de limpieza:

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.Scanner;

class ManualRead {
    static void firstLine(Path file) throws IOException {
        Scanner sc = null;
        try {
            sc = new Scanner(file, StandardCharsets.UTF_8);
            if (sc.hasNextLine()) System.out.println(sc.nextLine());
            if (sc.ioException() != null) throw sc.ioException();
        } finally {
            if (sc != null) sc.close();
        }
    }
}

Si la apertura falla, sc sigue siendo null, por lo que la comprobación evita que la limpieza lance una nueva excepción de referencia nula. Para los objetos que se pueden cerrar, try-with-resources elimina esta gestión y maneja los fallos simultáneos de forma más segura.

finally no garantiza que la máquina siga funcionando. System.exit termina la JVM sin ejecutar esta limpieza; un fallo o un corte de energía también la impiden. Un bucle infinito que nunca sale del bloque tampoco llega nunca a su finally.

Puntos clave

  • finally se ejecuta al terminar normalmente, con excepciones capturadas y no capturadas, y con transferencias de control como return.
  • Una expresión de retorno se evalúa antes de que se ejecute la limpieza.
  • El código posterior a una sentencia try se omite cuando se propaga una excepción; aun así se llega a finally.
  • Un retorno o una excepción lanzada en finally pueden ocultar el resultado original.
  • Try-with-resources es la opción habitual para cerrar recursos de archivos.
  • La terminación de la JVM o un bloque que nunca termina pueden impedir la limpieza.
3

Lanza excepciones y diseña las tuyas

Una solicitud no válida es más fácil de diagnosticar antes de que cambie un objeto. Tus métodos pueden rechazar argumentos o estados incorrectos con excepciones estándar y dar a conocer problemas del dominio mediante clases personalizadas. La declaración del método informa a quienes llaman de los fallos comprobados; la herencia limita lo que puede añadir un método que sobrescribe otro. Al transformar un fallo de bajo nivel en otro más útil, conserva su causa para que quien llama reciba tanto el contexto como la información de diagnóstico original.

3.1 Señala argumentos y estados no válidos

Tus métodos pueden rechazar solicitudes no válidas antes de cambiar un objeto. Elige una excepción que identifique el problema y permita responder a quien llama.

Lanza un objeto en el momento
class Percentage {
    private int value;

    public void setPercentage(int value) {
        if (value < 0 || value > 100) {
            throw new IllegalArgumentException(
                "percentage must be 0 to 100, was " + value);
        }
        this.value = value;
    }
}

Llamar a setPercentage(120) lanza una excepción con el mensaje percentage must be 0 to 100, was 120. La asignación no se ha ejecutado, por lo que el campo conserva su valor anterior. Esto es fallo inmediato: informa de la solicitud no válida en el punto donde puedes explicarla. La misma comprobación en un constructor impide que se devuelva un objeto no válido.

throw necesita un objeto de excepción, como en throw new IllegalArgumentException("bad quantity");. Un nombre de clase por sí solo no es un objeto. Una sentencia normal situada directamente después de un throw incondicional en el mismo bloque es inalcanzable.

ProblemaExcepción estándar
Un argumento tiene un valor no válidoIllegalArgumentException
El objeto está en un estado incorrecto para la llamadaIllegalStateException
Una referencia a objeto requerida es nullNullPointerException
La clase no ofrece la operaciónUnsupportedOperationException
La posición está fuera de una colecciónIndexOutOfBoundsException

Objects.requireNonNull(name, "name must not be null"), de java.util.Objects, es una forma cómoda de comprobar si hay un valor nulo. Que un pedido ya enviado rechace otro artículo es un problema de estado; una cantidad negativa de artículos es un problema de argumento.

Declara qué puede salir del método

Un método auxiliar de lectura de archivos puede declarar su fallo comprobado:

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

class NameLoader {
    static List<String> loadNames(Path file) throws IOException {
        return Files.readAllLines(file);
    }
}

throw es una sentencia ejecutable. throws pertenece a la declaración del método e indica a quienes llaman qué fallos comprobados deben manejar. No captura un fallo ni hace que el método continúe después de él. Cada método que llama debe capturar IOException o declararla a su vez. Una cláusula catch también puede volver a lanzar el mismo objeto con throw e;.

Captura la excepción donde sea posible dar una respuesta útil. Un método auxiliar normalmente no puede pedir al usuario que seleccione otro archivo, pero main sí. Imprimir «error» y devolver una lista vacía haría que se confundiera un archivo inexistente con uno realmente vacío. Un pequeño experimento puede permitir que main declare throws IOException; un programa terminado maneja los fallos esperados con mensajes útiles. Los tipos no comprobados pueden declararse como documentación aunque el compilador no lo exija.

Respeta el contrato heredado

Si una interfaz declara read() throws IOException, un método que lo sobrescribe puede declarar IOException, una subclase comprobada más específica o ninguna excepción comprobada. No puede ampliar la declaración a Exception. Puede declarar tipos no comprobados. Un método que sobrescribe Object.toString() no puede añadir IOException, ya que el método heredado no declara excepciones comprobadas. Las llamadas mediante el tipo de interfaz siguen teniendo que manejar su IOException declarada, aunque una implementación no declare ninguna.

Puntos clave

  • Usa throw con un objeto de excepción para detener una operación no válida.
  • Valida antes de cambiar campos o colecciones.
  • throws declara un posible fallo; no lo maneja.
  • Captura la excepción donde sea posible recuperarse de forma útil; de lo contrario, pasa el fallo a quien llama.
  • Los métodos que sobrescriben otros no pueden añadir excepciones comprobadas nuevas o más generales.

3.2 Describe fallos del dominio y conserva sus causas

Una excepción estándar suele ser suficiente. Crea una clase personalizada cuando quienes llaman necesiten reconocer un problema específico del programa, como existencias insuficientes o un registro de datos mal formado, y responder de forma diferente.

Elige la superclase de forma deliberada

Extender Exception crea una excepción comprobada. Extender RuntimeException crea una excepción no comprobada. Usa el diseño comprobado cuando quienes llaman deban prever un fallo recuperable del dominio; usa el diseño no comprobado para un uso incorrecto o un fallo de programación.

class OutOfStockException extends Exception {
    public OutOfStockException(String message) {
        super(message);
    }
}

super(message) almacena el mensaje en el mecanismo heredado de excepciones, por lo que getMessage() lo devuelve. Por convención, el nombre de la clase termina en Exception. Los campos adicionales y los métodos de acceso pueden ofrecer detalles estructurados, como las cantidades solicitada y disponible.

Mantén las existencias sin cambios tras un fallo
import java.util.HashMap;

class Inventory {
    private final HashMap<String, Integer> stock = new HashMap<>();

    Inventory() {
        stock.put("pens", 12);
    }

    void remove(String item, int quantity) throws OutOfStockException {
        if (quantity <= 0) {
            throw new IllegalArgumentException("quantity must be positive");
        }
        int available = stock.getOrDefault(item, 0);
        if (quantity > available) {
            throw new OutOfStockException("Requested " + quantity
                + " of " + item + ", only " + available + " in stock");
        }
        stock.put(item, available - quantity);
    }
}

Partiendo de 12 bolígrafos, retirar 5 deja 7. Una solicitud posterior de 10 lanza una excepción y quedan 7 porque la actualización se realiza después de todas las comprobaciones. Quien llama debe manejar o declarar el fallo comprobado de existencias; el fallo por cantidad no válida es no comprobado. Un programa que necesite una respuesta distinta para un artículo desconocido podría usar una UnknownItemException relacionada, con ambos tipos del dominio bajo una clase base InventoryException.

Envuelve sin perder el problema original

Un analizador puede transformar un fallo de conversión de bajo nivel en un fallo de un registro:

class InvalidRecordException extends Exception {
    public InvalidRecordException(String message) {
        super(message);
    }
    public InvalidRecordException(String message, Throwable cause) {
        super(message, cause);
    }
}

Dentro del método de análisis, un manejador puede hacer lo siguiente:

catch (NumberFormatException e) {
    throw new InvalidRecordException(
        "Line 3: quantity is not a number: x", e);
}

La excepción envoltorio proporciona a quien llama una categoría significativa y un número de línea. Su getCause() devuelve la NumberFormatException original y una traza impresa conserva una sección Caused by:. Construir una nueva excepción solo con el mensaje anterior pierde el objeto original y su traza.

java.io.UncheckedIOException es una clase envoltorio no comprobada ya disponible, específica para IOException. Sus constructores aceptan la causa, con un mensaje opcional. Puede transmitir un fallo de archivo a través de un método que sobrescribe otro y no puede añadir una declaración comprobada. Envolver cambia el tipo que ve quien llama; no repara el problema del archivo. Mantén las decisiones normales de los bucles como condiciones y break, sin inventar excepciones para el flujo habitual.

Puntos clave

  • Las clases personalizadas permiten a quienes llaman reconocer fallos significativos del dominio.
  • Extiende Exception para una clase comprobada o RuntimeException para una clase no comprobada.
  • Llama a super(message) para conservar un diagnóstico útil.
  • Valida la solicitud completa antes de actualizar el estado.
  • Pasa la excepción original como causa cuando la envuelvas.
  • UncheckedIOException transmite una IOException como fallo no comprobado.
4

Localiza archivos y cierra recursos de forma segura

Un archivo de texto debe encontrarse, decodificarse y cerrarse correctamente. Una ruta relativa depende del directorio de trabajo, mientras que los bytes se convierten en caracteres legibles solo con la codificación adecuada. El texto numérico y los fines de línea plantean sus propias decisiones de portabilidad. Una vez abierto un archivo, try-with-resources lo libera en cada salida y mantiene visible el fallo principal si también falla el cierre. Estas decisiones hacen más fiable el código de lectura y escritura posterior.

4.1 Haz que los archivos de texto funcionen en distintos equipos

Un archivo almacena bytes, mientras que tu programa trabaja con caracteres y números. Para leer correctamente se necesitan la ubicación y la codificación de caracteres adecuadas, además de una convención clara para las líneas y el texto numérico.

Encuentra la ubicación real

Una ruta relativa comienza en el directorio de trabajo del programa. No comienza en la carpeta que contiene el código fuente. Una ruta absoluta comienza en la raíz del sistema de archivos, como /home/ana/data/scores.txt, o en la raíz de una unidad en Windows.

Path file = Path.of("data", "scores.txt");
System.out.println(System.getProperty("user.dir"));
System.out.println(file.toAbsolutePath());
System.out.println(file.getFileName());

Importa java.nio.file.Path. Crear este Path no abre nada ni comprueba si existe. toAbsolutePath() revela dónde buscará Java y getFileName() da scores.txt. Un IDE suele usar la carpeta del proyecto como directorio de trabajo. Las barras diagonales en "data/scores.txt" funcionan en Windows, Linux y macOS. Un literal de ruta de Windows que use barras invertidas necesita secuencias de escape, como en "C:\\data\\scores.txt". La clase más antigua java.io.File también representa una ubicación; convierte con toPath() o toFile().

Relaciona los bytes con los caracteres

UTF-8 codifica todos los caracteres Unicode. Los caracteres latinos básicos ocupan un byte; los demás ocupan de dos a cuatro. El texto «café» contiene cuatro caracteres pero cinco bytes en UTF-8 porque «é» ocupa dos. Leer esos bytes como ISO-8859-1 puede producir «café». Usa la codificación que se utilizó al escribir.

Los métodos de texto de Files usan UTF-8 de forma predeterminada. Las clases como FileWriter y un scanner abierto sin una codificación usan la codificación predeterminada, que pasó a ser UTF-8 en Java 18; las instalaciones anteriores pueden diferir. StandardCharsets.UTF_8, de java.nio.charset, hace explícita la elección. Los bytes no válidos leídos por Files.readAllLines producen MalformedInputException, una subclase de IOException.

Lee líneas sin restos de los fines de línea
ConvenciónSecuencia de escape en cadenas Java
Fin de línea de Linux y macOS\n
Fin de línea habitual de Windows\r\n

Con un terminador después de cada línea, «a» y «b» necesitan cuatro bytes con fines de línea LF y seis con fines de línea CRLF. BufferedReader.readLine(), Files.readAllLines y Scanner.nextLine() eliminan los fines de línea reconocidos. Dividir una cadena completa con split("\n") deja el \r de Windows, por lo que convertir "12\r" con parseInt falla. Prefiere los métodos de lectura de líneas o elimina los espacios del texto. System.lineSeparator() y el formato %n producen el fin de línea del sistema actual.

Mantén la coherencia de los archivos numéricos

Integer.parseInt acepta texto entero, sin separador decimal. Double.parseDouble("3.5") acepta un punto; Double.parseDouble("3,5") falla. Estos métodos de análisis ignoran la configuración regional. Los métodos numéricos de Scanner y el formato decimal normal siguen la configuración regional, por lo que una configuración alemana u holandesa puede esperar «3,5» y producir «3,50». Usa scanner.useLocale(Locale.ROOT) y String.format(Locale.ROOT, "%.2f", value) para datos con punto decimal; importa java.util.Locale.

Las ubicaciones inexistentes suelen producir NoSuchFileException con Files o Scanner(Path), mientras que los constructores más antiguos que reciben nombres de archivo pueden producir FileNotFoundException. Los fallos de permisos pueden producir AccessDeniedException. Estos son fallos de entrada y salida comprobados: una expresión de ruta correcta por sí sola no puede impedirlos.

Puntos clave

  • Las rutas relativas se resuelven desde el directorio de trabajo.
  • Crear un Path no abre ni comprueba el archivo.
  • Usa la misma codificación para leer y escribir; elige UTF-8 explícitamente cuando los valores predeterminados puedan variar.
  • Los métodos de lectura de líneas eliminan los terminadores LF, CRLF y CR.
  • Double.parseDouble usa un punto; los métodos numéricos que dependen de la configuración regional necesitan una configuración elegida.
  • Abrir y leer archivos sigue requiriendo el manejo de excepciones comprobadas.

4.2 Deja que Java cierre cada recurso abierto

Un archivo abierto usa un recurso del sistema operativo. Cerrarlo lo libera y vacía la salida pendiente del búfer de un escritor. Olvidar el cierre puede agotar los límites de archivos abiertos, perder texto almacenado en el búfer o impedir que otro programa modifique el archivo.

Declara los recursos en la cabecera de try
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;

class Lines {
    static void show(Path file) throws IOException {
        try (BufferedReader in =
                Files.newBufferedReader(file, StandardCharsets.UTF_8)) {
            String line;
            while ((line = in.readLine()) != null) {
                System.out.println(line);
            }
        }
    }
}

La cabecera abre el lector. El cuerpo lo usa y Java lo cierra cuando el cuerpo termina normalmente, retorna o lanza una excepción. No se necesita un finally separado. Aquí no hay ningún manejador, por lo que cualquier fallo comprobado sigue pasando a quien llama mediante throws IOException.

Un recurso debe implementar AutoCloseable. Esa interfaz declara close() y permite Exception; su subinterfaz Closeable restringe el fallo comprobado declarado a IOException. Los lectores, escritores y Scanner cumplen el requisito. Un String no. Las variables de la cabecera son implícitamente final y están disponibles en el cuerpo, no en los bloques catch o finally de esa sentencia. Java 9 y posteriores también permiten una variable existente final o efectivamente final: try (in) { ... }.

Cierra en orden inverso

Separa los recursos con puntos y coma:

try (BufferedReader in = Files.newBufferedReader(source);
     java.io.BufferedWriter out = Files.newBufferedWriter(target)) {
    String line;
    while ((line = in.readLine()) != null) {
        out.write(line);
        out.newLine();
    }
}

Este es un bloque dentro de un método que declara IOException, con rutas source y target distintas. Java abre primero in, luego out, y cierra out antes que in. Si falla la apertura de out, el lector ya abierto también se cierra. Abrir un escritor sobre la ruta de entrada truncaría esa entrada, por lo que las rutas deben ser distintas para esta copia directa.

El cierre de recursos ocurre antes de las cláusulas catch y finally que pertenecen a la misma sentencia. Esos manejadores pueden recibir fallos de apertura, uso o cierre de los recursos.

Mantén visible el fallo principal

Supón que el cuerpo lanza una excepción de registro y después el cierre del lector lanza una IOException. Try-with-resources propaga la excepción del cuerpo y adjunta el fallo de cierre como suprimido. getSuppressed() lo recupera y la traza imprime una sección Suppressed:. El fallo original del cuerpo permanece visible. Si el cuerpo tiene éxito y solo falla el cierre, la excepción de cierre se propaga normalmente.

Si se producen varios fallos durante el cierre, Java sigue intentando cerrar los recursos restantes. En cambio, un simple finally { resource.close(); } puede sustituir un fallo pendiente del cuerpo por uno de limpieza.

Usa este patrón para los recursos de archivos de los que tu código es responsable. Cerrar un scanner sobre System.in también cierra la entrada de teclado del programa e impide lecturas posteriores. Mantén la responsabilidad de la entrada estándar compartida a nivel del programa en vez de cerrarla en un método auxiliar.

Puntos clave

  • Try-with-resources cierra los recursos abiertos correctamente tanto en salidas normales como excepcionales.
  • Solo los objetos AutoCloseable pueden ser recursos.
  • Los recursos se abren de izquierda a derecha y se cierran de derecha a izquierda.
  • El cierre precede a los bloques catch y finally de la misma sentencia.
  • Un fallo del cuerpo sigue siendo el principal; los fallos posteriores de cierre se suprimen.
  • El cierre automático no sustituye el manejo mediante captura o declaración.
  • Cerrar un scanner también cierra su fuente de entrada si esta se puede cerrar.
5

Lee y escribe archivos de texto

El procesamiento de archivos conecta los bytes externos con los objetos y resultados que usa tu programa. Lee líneas con un método adecuado al tamaño de la entrada, valida los campos antes de convertirlos y escribe eligiendo deliberadamente entre sustituir o añadir al final. Un informe completo necesita respuestas diferentes para un registro incorrecto y un archivo inutilizable. Construye el resultado antes de guardarlo y después usa una salida temporal y un movimiento atómico admitido cuando debas proteger un destino existente.

5.1 Lee líneas y conviértelas en objetos

La lectura te proporciona texto. El análisis da significado a ese texto: un recuento, una edad o un objeto. Mantén separadas estas dos operaciones para que un registro incorrecto no parezca un fallo de lectura del archivo.

Elige cuánto mantener en memoria
MétodoResultado y uso
Files.readAllLines(path)Una lista con todas las líneas; cómoda para archivos pequeños
Files.readString(path)Una cadena que conserva los fines de línea
BufferedReader.readLine()Una línea cada vez; null señala el final
Scanner.hasNextLine() / nextLine()Lectura cómoda línea por línea

Importa java.nio.file.Files y Path, además de los tipos de lector o colección que utilices. Los métodos de texto de Files usan UTF-8 de forma predeterminada. Un BufferedReader debe usarse en try-with-resources e informa de los fallos de lectura con IOException. Leer una línea cada vez evita mantener toda la entrada en memoria, salvo que tu procesamiento almacene después todos los registros.

Un scanner también necesita cerrarse y requiere una comprobación adicional de fallos:

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.Scanner;

class ScanFile {
    static void show(Path file) throws IOException {
        try (Scanner sc = new Scanner(file, StandardCharsets.UTF_8)) {
            while (sc.hasNextLine()) {
                System.out.println(sc.nextLine());
            }
            if (sc.ioException() != null) throw sc.ioException();
        }
    }
}

La apertura puede lanzar una excepción directamente. Durante la lectura, Scanner trata un fallo subyacente de entrada y salida como el final de la entrada y lo almacena; ioException() permite consultarlo. Sin esa comprobación final, una lectura parcial puede parecer satisfactoria.

Cuenta las líneas físicas y después analiza

Para las líneas de entrada «12», «15», «abc», una línea vacía y «9», incrementa el número de línea antes de decidir si omites una línea en blanco. Convierte cada línea que no esté en blanco con Integer.parseInt(line.trim()) dentro de su propio try. Informa «Line 3: not a number: abc» y continúa. La suma válida es 36 y el recuento es 3, lo que da una media de 12,0. Calcula (double) sum / count para conservar un resultado fraccionario y comprueba primero que el recuento no sea cero.

Comprueba los campos antes de acceder por índice

Los datos sencillos separados por comas pueden convertirse en objetos. Aquí la primera línea es un encabezado obligatorio; cada registro restante tiene un nombre no vacío y una edad entera:

String[] parts = line.split(",", -1);
if (parts.length != 2 || parts[0].isBlank() || parts[1].isBlank()) {
    System.out.println("Line " + lineNumber + ": expected name and age");
    continue;
}
try {
    int age = Integer.parseInt(parts[1].trim());
    people.add(new Person(parts[0].trim(), age));
} catch (NumberFormatException e) {
    System.out.println("Line " + lineNumber + ": invalid age");
}

Este fragmento del cuerpo de un bucle presupone line, lineNumber, un List<Person> llamado people y un constructor Person(String, int). Omite el encabezado «name,age» antes de este paso de análisis; de lo contrario, «age» falla en la conversión numérica. Los registros «Ana,34», «Ben,29» y «Chen,41» suman 104 años y tienen una media aproximada de 34,67.

Un simple split(",") descarta los campos vacíos finales: «Eve,» produce una sola parte. El límite -1 conserva el segundo campo vacío para que la validación pueda notificarlo. Comprueba siempre la longitud antes de parts[1]. Dividir por sí solo no maneja las comas entre comillas, como la del nombre en ""Smith, Ana",34"; el CSV completo necesita un analizador CSV.

Puntos clave

  • Elige métodos que lean todo el archivo para entradas de tamaño manejable o un bucle con lector para las grandes.
  • Comprueba Scanner.ioException() después de leer para detectar un fallo de lectura oculto.
  • Cuenta las líneas originales del archivo incluso cuando se omitan líneas en blanco o registros.
  • Comprueba el número de campos y los valores obligatorios antes de acceder por índice y convertir.
  • Omite el encabezado antes de analizar los registros.
  • La división simple no puede analizar campos CSV entrecomillados.

5.2 Escribe el texto completo y añade contenido al final de forma deliberada

Abrir un archivo de salida puede modificarlo de inmediato. Elige entre sustituir o añadir al final antes de abrir el escritor y termina cerrándolo para que la salida almacenada en el búfer no quede en memoria.

Sustituye o añade al final

Files.writeString(path, text) escribe una cadena. Files.write(path, lines) escribe un iterable de líneas y añade el separador de línea del sistema después de cada una, incluida la última. Con sus opciones predeterminadas, ambos crean un archivo inexistente y truncan uno existente.

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;

class RunLog {
    static void recordStart(Path log) throws IOException {
        Files.writeString(log, "started" + System.lineSeparator(),
            StandardCharsets.UTF_8,
            StandardOpenOption.CREATE, StandardOpenOption.APPEND);
    }
}

CREATE permite crear un archivo nuevo; APPEND conserva el contenido anterior y añade al final. APPEND por sí solo falla si el archivo no existe. Añadir al final no inserta un separador ausente antes de tu texto: si un archivo existente termina a mitad de una línea, los siguientes caracteres continúan esa línea.

La clase más antigua FileWriter tiene un indicador de adición: new FileWriter("log.txt", StandardCharsets.UTF_8, true). Sin adición al final, un nuevo FileWriter o un PrintWriter creado con un nombre de archivo también trunca un archivo existente. Nunca abras un escritor que sustituya el contenido sobre una entrada que aún necesites leer.

Elige un escritor y detecta los fallos

BufferedWriter admite write y newLine(), e informa de los fallos de escritura como excepciones comprobadas:

import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Locale;

class ReportWriter {
    static void write(Path file) throws IOException {
        try (BufferedWriter out =
                Files.newBufferedWriter(file, StandardCharsets.UTF_8)) {
            out.write("Readings: 3");
            out.newLine();
            out.write(String.format(Locale.ROOT, "Average: %.2f", 3.0));
            out.newLine();
        }
    }
}

El archivo tiene dos líneas: «Readings: 3» y «Average: 3.00». Locale.ROOT fija el punto decimal. newLine(), println y %n usan el fin de línea de la plataforma; un \n literal escribe LF en todos los sistemas.

Un PrintWriter ofrece los prácticos print, println y printf, pero esos métodos registran los fallos de entrada y salida en vez de lanzarlos. checkError() vacía el búfer e informa de su indicador de error. Para comprobar también los fallos del cierre final, conserva el acceso al escritor y comprueba después de cerrarlo. Para código que deba propagar de forma fiable los fallos de escritura, usa BufferedWriter o los métodos de Files.

Completa el ciclo de escritura y lectura

Los escritores almacenan la salida en un búfer. flush() envía el texto pendiente; close() vacía el búfer y libera el archivo. Try-with-resources garantiza que se intente el cierre en cada salida, pero no puede hacer que una escritura en disco tenga éxito.

Para guardar una persona, escribe el nombre, una coma y la edad entera, seguidos de un fin de línea. Da formato a los decimales con Locale.ROOT para que un Double.parseDouble posterior pueda leerlos. Una carpeta superior inexistente no se crea al abrir un archivo: usa Files.createDirectories(folder) cuando se pretenda crearla o informa del fallo. Una escritura puede fallar después del truncamiento o de una salida parcial; usa una salida temporal y un movimiento atómico cuando debas proteger el destino.

Puntos clave

  • La escritura predeterminada crea un archivo inexistente y trunca uno existente.
  • Usa CREATE con APPEND para conservar el contenido anterior y permitir un registro nuevo.
  • El cierre vacía la salida almacenada en el búfer y libera el recurso.
  • PrintWriter registra los errores de escritura; checkError() permite consultarlos.
  • BufferedWriter y los métodos de Files propagan los fallos de entrada y salida.
  • Usa UTF-8 y Locale.ROOT para que el texto pueda escribirse y volver a leerse en distintos sistemas.
  • Escribir un archivo no crea las carpetas superiores que faltan.

5.3 Crea un informe sin ocultar los fallos

Un procesador de archivos robusto necesita dos niveles de recuperación. Un registro incorrecto puede omitirse y notificarse; un fallo al leer o guardar el archivo detiene la tarea. Calcula un resultado completo antes de tocar su destino.

Lee, valida, calcula y guarda

El programa completo siguiente lee el encabezado opcional «date,temperature» seguido de registros sencillos de dos campos. Las fechas son etiquetas no vacías; las temperaturas son números finitos en grados Celsius. Omite y notifica los registros mal formados, incluidas las líneas en blanco. La excepción comprobada anidada mantiene separados los problemas de registros de los problemas de archivos.

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.AtomicMoveNotSupportedException;
import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.List;
import java.util.Locale;

public class TemperatureReport {
    static class InvalidRecordException extends Exception {
        InvalidRecordException(String message) { super(message); }
        InvalidRecordException(String message, Throwable cause) {
            super(message, cause);
        }
    }

    static List<String> readLines(Path file) throws IOException {
        return Files.readAllLines(file, StandardCharsets.UTF_8);
    }

    static double parseTemperature(String line, int lineNumber)
            throws InvalidRecordException {
        String[] parts = line.split(",", -1);
        if (parts.length != 2 || parts[0].isBlank()
                || parts[1].isBlank()) {
            throw new InvalidRecordException("Line " + lineNumber
                + ": expected a date label and a temperature");
        }
        try {
            double value = Double.parseDouble(parts[1].trim());
            if (!Double.isFinite(value)) {
                throw new InvalidRecordException("Line " + lineNumber
                    + ": temperature must be finite");
            }
            return value;
        } catch (NumberFormatException e) {
            throw new InvalidRecordException("Line " + lineNumber
                + ": not a number: " + parts[1], e);
        }
    }

    static String summarize(List<String> lines) {
        int count = 0;
        int skipped = 0;
        double sum = 0;
        double min = Double.POSITIVE_INFINITY;
        double max = Double.NEGATIVE_INFINITY;
        for (int i = 0; i < lines.size(); i++) {
            String line = lines.get(i);
            if (i == 0 && line.equals("date,temperature")) continue;
            try {
                double value = parseTemperature(line, i + 1);
                sum += value;
                count++;
                min = Math.min(min, value);
                max = Math.max(max, value);
            } catch (InvalidRecordException e) {
                skipped++;
                System.err.println(e.getMessage());
            }
        }
        if (count == 0) {
            return String.format(Locale.ROOT,
                "No valid readings%nSkipped lines: %d%n", skipped);
        }
        return String.format(Locale.ROOT,
            "Valid readings: %d%nAverage (°C): %.2f%n"
                + "Minimum (°C): %.2f%nMaximum (°C): %.2f%n"
                + "Skipped lines: %d%n",
            count, sum / count, min, max, skipped);
    }

    static void writeSummary(Path file, String text) throws IOException {
        Path target = file.toAbsolutePath();
        Path temp = Files.createTempFile(target.getParent(), "report-", ".tmp");
        try {
            Files.writeString(temp, text, StandardCharsets.UTF_8);
            Files.move(temp, target, StandardCopyOption.ATOMIC_MOVE);
        } catch (IOException e) {
            try {
                Files.deleteIfExists(temp);
            } catch (IOException cleanup) {
                e.addSuppressed(cleanup);
            }
            throw e;
        }
    }

    public static void main(String[] args) {
        Path input = Path.of("readings.csv");
        Path output = Path.of("summary.txt");
        try {
            List<String> lines = readLines(input);
            String report = summarize(lines);
            writeSummary(output, report);
            System.out.println("Saved: " + output.toAbsolutePath());
        } catch (NoSuchFileException e) {
            System.err.println("File or folder not found: " + e.getFile());
        } catch (AtomicMoveNotSupportedException e) {
            System.err.println("Could not save atomically: "
                + output.toAbsolutePath());
        } catch (IOException e) {
            System.err.println("Could not process " + input.toAbsolutePath()
                + " or save " + output.toAbsolutePath() + ": " + e.getMessage());
        }
    }
}
Sigue una ejecución

Usa estas cinco líneas de entrada sin encabezado:

2026-03-01,4.5
2026-03-02,6.0
2026-03-03,abc
2026-03-04,-1.5
missing comma

Las líneas 1, 2 y 4 producen tres lecturas válidas. La suma es 9,0; la media es 3,00 °C, la mínima es -1,50 °C y la máxima es 6,00 °C. Las líneas 3 y 5 producen mensajes de diagnóstico y el informe registra dos líneas omitidas. El manejador de análisis está dentro del bucle, por lo que cada registro incorrecto deja accesibles los registros posteriores. Actualizar los totales solo después de un análisis correcto mantiene fuera los valores rechazados.

Double.parseDouble acepta cadenas especiales como «NaN» e «Infinity». Double.isFinite las rechaza aquí porque no pueden servir como temperaturas medidas normales. Un archivo vacío, un archivo con solo encabezado o registros todos no válidos llegan a la rama de recuento cero antes de la división o del uso de la mínima y la máxima iniciales.

Protege el destino

La lectura y el cálculo terminan antes de que comience el guardado. Files.writeString abre y cierra su propio archivo, pero puede fallar después de escribir una parte. Por eso el programa escribe en un archivo temporal de la carpeta de destino, lo cierra y solicita ATOMIC_MOVE. El movimiento hace visible el resultado terminado como una sola operación del sistema de archivos cuando se admite.

La sustitución atómica de un destino existente depende de la implementación. El programa informa de un movimiento o sustitución no admitidos y nunca lo reintenta con un movimiento no atómico. Un fallo de limpieza se adjunta a la excepción original en lugar de sustituirla. La visibilidad atómica no garantiza la supervivencia a un corte de energía.

Comprobar Files.exists(input) de antemano no puede garantizar la lectura posterior: un archivo puede desaparecer o volverse inaccesible después de la comprobación. Maneja la operación real. Antes de confiar en un procesador, pruébalo con una entrada inexistente, carpetas de salida inexistentes, archivos vacíos y con solo encabezado, fines de línea CRLF, texto acentuado y registros mal formados. Los mensajes al usuario deben nombrar la ruta que falló; depurar una excepción envoltorio también requiere su causa original y su traza de la pila.

Puntos clave

  • Maneja los fallos de registros dentro del bucle y los fallos del archivo completo fuera de él.
  • Valida un registro completo antes de actualizar los recuentos o totales.
  • Comprueba si hay cero registros válidos antes de calcular una media.
  • Termina la lectura y el cálculo antes de abrir la salida.
  • Escribe y cierra un archivo temporal, y después solicita un movimiento atómico para proteger el destino.
  • Informa de una sustitución atómica no admitida en vez de recurrir a otra opción sin avisar.
  • Mantén disponibles las causas originales y los fallos de limpieza para el diagnóstico.

Ejemplos de Excepciones y archivos en Java

5 Lecciones Interactivas

1

Sigue un fallo hasta su causa

11 pasos
Interpreta una traza de excepción, relaciónala con las llamadas activas y usa la herencia para clasificar el fallo.
  1. 1
    IntroducciónUn programa puede compilar y aun así fallar

    Un valor de entrada puede hacer que código Java válido falle mientras se ejecuta. El objeto de excepción indica qué tipo de problema ocurrió y la traza de la pila muestra qué llamadas a métodos estaban activas.

    Sigue primero una conversión entera fallida. Después usa las mismas reglas de herencia que permiten utilizar objetos de subclases como objetos de superclases para decidir qué exige manejar el compilador.

  2. 2
    EjemploObserva cómo se detiene la conversión

    Un método loadCount ejecuta estas sentencias:

    System.out.print("start ");
    int count = Integer.parseInt("eight");
    System.out.print("finish");
    

    Imprime start y después lanza NumberFormatException. La asignación no se completa y se omite finish. Un manejador que coincida puede tomar el control, pero la sentencia fallida no se reanuda después de la recuperación.

  3. 3
    ExplicaciónSigue las llamadas activas

    Supón que main llamó a loadCount, que llamó a Integer.parseInt. Esas llamadas forman parte de la pila de llamadas. La excepción se propaga hacia fuera cuando un método no tiene un manejador que coincida.

    parseInt falla primero, loadCount no puede terminar su trabajo normal y quien llamó tiene la oportunidad de manejar el fallo. Si sale de main sin manejarse, Java informa de la excepción y el hilo principal termina.

  4. 4
    EjemploEncuentra el primer marco de tu código

    Una traza puede incluir estos marcos de la aplicación después de los marcos de la biblioteca de Java:

    at Counts.loadCount(Counts.java:14)
    at Counts.main(Counts.java:5)
    

    Inspecciona primero la línea 14: es la llamada de tu código más cercana al punto de detección. La línea 5 indica dónde se llamó a loadCount. La primera línea de la excepción indica su clase y su mensaje; no confundas el marco inferior de quien llamó con la sentencia que usó por primera vez el texto incorrecto.

  5. 5
    DesafíoEncuentra la salida omitida

    Un método auxiliar imprime A, llama a Integer.parseInt("q2") y después imprimiría B. Quien lo llama captura NumberFormatException e imprime C. ¿Qué letras se imprimen y por qué?

    ---reveal---

    A y después C. La conversión lanza una excepción antes de B; la propagación lleva el fallo al manejador correspondiente de quien llamó. Las sentencias restantes del método auxiliar se abandonan, por lo que la recuperación no vuelve a imprimir B.

  6. 6
    ConsejoBusca más allá de la sentencia detectada

    La sentencia donde se detecta un fallo puede estar usando un valor incorrecto creado antes. Un fallo de referencia nula indica que debes seguir dónde debería haber recibido un objeto esa referencia.

    Usa getMessage() para el texto de diagnóstico y printStackTrace() para la cadena de llamadas. Un mensaje puede ser null; una sección Caused by: proporciona otra excepción conservada dentro de una excepción envoltorio.

  7. 7
    ExplicaciónUsa la cadena de superclases

    Throwable es la clase base de los objetos que pueden lanzarse. Sus ramas principales son Error y Exception; RuntimeException se encuentra bajo Exception.

    RuntimeException, Error y todas las subclases de cualquiera de ellas son no comprobadas. Las demás subclases de Throwable son comprobadas. Ambas categorías fallan durante la ejecución; «comprobada» describe la comprobación del manejo por el compilador, no un momento distinto en el que se lanza la excepción.

  8. 8
    EjemploCompara un analizador y un lector de archivos

    NumberFormatException extiende IllegalArgumentException y esta extiende RuntimeException, por lo que una llamada a Integer.parseInt no tiene un manejador obligatorio.

    IOException extiende Exception fuera de esa rama. Una llamada a Files.readString debe capturar su posible IOException o declararla con throws. Un archivo puede fallar por causas externas aunque el código que llama sea correcto.

  9. 9
    DesafíoClasifica un fallo desconocido

    BadRecordException extiende Exception directamente. Un método auxiliar declara que puede lanzar este tipo. ¿Qué debe hacer quien lo llama y cuándo se comprueba esa obligación?

    ---reveal---

    Capturarla o declarar un tipo comprobado aplicable en la declaración del método que llama. El compilador exige esa obligación porque la clase está fuera de las ramas no comprobadas. Que una ejecución concreta tenga éxito no elimina el requisito de declaración.

  10. 10
    DesafíoExplica un manejador sorprendentemente general

    Un bloque de lectura de archivos captura Exception e imprime «Problema de archivo». En cambio, falla con una NullPointerException causada por un error. ¿La recibirá el manejador y es fiable ese mensaje?

    ---reveal---

    Sí: NullPointerException extiende RuntimeException, que extiende Exception. El mensaje es engañoso porque este fallo es un error del código, no una prueba de un problema de archivo. Lee la traza y limita el manejador esperado a los fallos que puede explicar.

  11. 11
    RepasoElige la siguiente acción de depuración

    Comienza la investigación de un fallo por su clase, su mensaje y el primer marco de la aplicación. Sigue a quienes llamaron y el origen de los valores incorrectos cuando la sentencia detectada por sí sola no explique la causa.

    Después comprueba la herencia antes de elegir el manejo: los fallos comprobados requieren una decisión visible para el compilador; los fallos no comprobados también necesitan corrección. Evita que los manejadores generales disimulen un tipo de problema como otro.

2

Sigue las rutas de recuperación y limpieza

12 pasos
Sigue una conversión de entrada fallida, elige el alcance y el orden de los manejadores y sigue finally en las salidas anticipadas.

Guarda esta unidad para seguir cada Lección Interactiva paso a paso.

  1. 1
    IntroducciónDecide qué debe ocurrir después
  2. 2
    EjemploRecupera la ejecución después de toda la sentencia
  3. 3
    ConsejoHaz que un reintento lea texto nuevo
  4. 4
    DesafíoCorrige el scanner atascado
  5. 5
    ExplicaciónDa una respuesta propia a un fallo específico
  6. 6
    EjemploDeja que el bucle continúe
  7. 7
    DesafíoMueve el límite protegido
  8. 8
    Idea claveComparte respuestas sin tipos que se solapen
  9. 9
    ExplicaciónLa limpieza se ejecuta antes de salir
  10. 10
    DesafíoSigue un fallo que no coincide
  11. 11
    DesafíoEvita que la limpieza oculte un fallo que debe reintentarse
  12. 12
    RepasoSigue la siguiente sentencia alcanzable
3

Rechaza una solicitud sin dañar el estado

11 pasos
Valida una operación de inventario, expón un fallo del dominio y envuelve un fallo de análisis conservando su causa.

Guarda esta unidad para seguir cada Lección Interactiva paso a paso.

  1. 1
    IntroducciónConserva un objeto utilizable
  2. 2
    EjemploValida antes de restar
  3. 3
    ExplicaciónDistingue el lanzamiento de la declaración
  4. 4
    DesafíoElige el fallo estándar adecuado
  5. 5
    ConexiónUn método sobrescrito mantiene las promesas a quienes llaman
  6. 6
    EjemploDa un tipo propio a las existencias insuficientes
  7. 7
    EjemploMantén separada la solicitud fallida
  8. 8
    DesafíoDecide qué estado se conserva
  9. 9
    ExplicaciónConserva el fallo de conversión original
  10. 10
    DesafíoTransmite un fallo de archivo mediante un método restringido
  11. 11
    RepasoDiseña una excepción que quien llama pueda usar
4

Abre el texto correcto y ciérralo de forma segura

12 pasos
Resuelve una ruta, ajusta las convenciones de texto y después sigue la apertura y el cierre de recursos y los fallos simultáneos.

Guarda esta unidad para seguir cada Lección Interactiva paso a paso.

  1. 1
    IntroducciónLa ubicación y el tiempo de vida importan
  2. 2
    EjemploResuelve desde el directorio de trabajo
  3. 3
    ExplicaciónDecodifica con la codificación utilizada al escribir
  4. 4
    ConsejoElimina un fin de línea completo
  5. 5
    DesafíoHaz que un decimal pueda escribirse y volver a leerse
  6. 6
    ExplicaciónDeclara un recurso para cerrarlo
  7. 7
    ConexiónUsa el contrato de cierre
  8. 8
    EjemploInvierte el orden de apertura
  9. 9
    DesafíoSigue una segunda apertura fallida
  10. 10
    Idea claveMantén un fallo del cuerpo como informe principal
  11. 11
    DesafíoDistingue el fallo de datos del fallo de limpieza
  12. 12
    RepasoInspecciona una operación de archivo en orden
5

Convierte lecturas en un informe fiable

16 pasos
Lee y valida registros sencillos, calcula los resultados aceptados y guarda la salida completa con una política clara ante fallos.

Guarda esta unidad para seguir cada Lección Interactiva paso a paso.

  1. 1
    IntroducciónUn informe necesita más que una aritmética correcta
  2. 2
    ExplicaciónElige cómo llegan las líneas
  3. 3
    EjemploDefine el registro antes de analizarlo
  4. 4
    EjemploValida antes de usar el segundo campo
  5. 5
    DesafíoLocaliza el registro rechazado
  6. 6
    ExplicaciónElige entre sustituir o añadir al final
  7. 7
    EjemploEscribe una línea de informe portátil
  8. 8
    ConsejoDetecta una escritura fallida
  9. 9
    DesafíoConserva las entradas antiguas y nuevas del registro
  10. 10
    ConexiónRecupera la ejecución en dos niveles distintos
  11. 11
    EjemploActualiza los totales solo después de validar
  12. 12
    DesafíoManeja un valor que se analiza pero no sirve
  13. 13
    ExplicaciónTermina la salida antes de sustituir el destino
  14. 14
    ConsejoMantén visible el fallo de guardado
  15. 15
    DesafíoElige qué puede notificarse con seguridad
  16. 16
    RepasoRevisa el procesador según la ruta de fallo

Ejercicios de Excepciones y archivos en Java

40 Preguntas de Práctica en 4 sets

Set 1: Sigue los fallos y elige una recuperación útil10 Preguntas de Práctica

Pregunta 1 de 10

Un BufferedReader ha llegado al final de su archivo. ¿Qué devuelve la siguiente llamada a readLine()?
  1. null
  2. Una cadena vacía.
  3. Una cadena que contiene "EOF".
  4. Una cadena que contiene "\n".
Mostrar respuestaOcultar respuesta
Respuesta: A
BufferedReader.readLine() devuelve null cuando no quedan caracteres para formar otra línea. Una cadena vacía representa una línea en blanco real, por lo que usarla como marca de final detendría la lectura demasiado pronto. Los terminadores de línea se eliminan de las líneas devueltas y no son una marca de fin de archivo.

Pregunta 2 de 10

Un arreglo tiene longitud 5. ¿Qué ocurre cuando el programa evalúa values[5]?
  1. Lee el quinto elemento del arreglo.
  2. Lanza ArrayIndexOutOfBoundsException.
  3. Devuelve el valor entero predeterminado 0.
  4. Lanza NumberFormatException.
Mostrar respuestaOcultar respuesta
Respuesta: B
Un arreglo de longitud 5 tiene índices válidos de 0 a 4, por lo que el índice 5 queda fuera. Java lanza ArrayIndexOutOfBoundsException en ese acceso. Contar cinco elementos no hace válido el índice 5: el quinto elemento está en el índice 4.

Pregunta 3 de 10

DataProblem extiende Exception directamente. ¿Qué obligación tiene un método cuando llama a un método auxiliar declarado con throws DataProblem?
  1. Capturar RuntimeException o declararla.
  2. Declararla solo si falla el método auxiliar.
  3. Manejarla solo cuando se ejecute el programa.
  4. Capturar DataProblem o declararla.
Mostrar respuestaOcultar respuesta
Respuesta: D
DataProblem es comprobada porque extiende Exception fuera de la rama de RuntimeException. El código que llama debe capturarla o declarar un tipo comprobado aplicable. El compilador comprueba la posibilidad declarada, aunque una llamada concreta tuviera éxito.

Pregunta 4 de 10

¿Qué letras se imprimen y en qué orden?

System.out.print("P");
try {
    int n = Integer.parseInt("7q");
    System.out.print("Q");
} catch (NumberFormatException e) {
    System.out.print("R");
}
System.out.print("S");
  1. PRS
  2. PQRS
  3. PR
  4. PS
Mostrar respuestaOcultar respuesta
Respuesta: A
Convertir «7q» lanza NumberFormatException antes de la sentencia que imprime Q. El manejador que coincide imprime R, después la ejecución continúa tras la sentencia e imprime S. La sentencia omitida no se ejecuta después de la recuperación, por lo que PQRS no puede ser la salida.

Pregunta 5 de 10

Un bloque puede lanzar NoSuchFileException u otra IOException. ¿Qué orden de captura da a cada una su propia respuesta?
  1. IOException, después NoSuchFileException.
  2. Exception, después NoSuchFileException.
  3. NoSuchFileException, después IOException.
  4. IOException | NoSuchFileException en una cláusula.
Mostrar respuestaOcultar respuesta
Respuesta: C
NoSuchFileException extiende IOException, por lo que su manejador específico debe aparecer primero. Colocar IOException primero capturaría ya todas las excepciones de archivo inexistente y haría inalcanzable el manejador posterior. Una captura múltiple tampoco puede combinar estos tipos relacionados.

Pregunta 6 de 10

¿Qué imprime y qué devuelve la llamada a pick()?

static int pick() {
    try {
        return 8;
    } finally {
        System.out.print("done");
    }
}
  1. Devuelve 8 sin imprimir nada.
  2. Imprime done y devuelve 8.
  3. Imprime done y no devuelve ningún valor.
  4. Imprime 8 y después devuelve done.
Mostrar respuestaOcultar respuesta
Respuesta: B
La expresión de retorno se evalúa, pero el método ejecuta finally antes de entregar ese valor a quien llamó. Por tanto, imprime done y devuelve 8. Un retorno dentro de try no omite la limpieza; solo una transferencia de control desde la limpieza que entre en conflicto sustituiría ese resultado.

Pregunta 7 de 10

Un método rechaza una capacidad negativa antes de asignarla a un campo. ¿Qué excepción estándar describe mejor el argumento no válido?
  1. IllegalArgumentException
  2. IllegalStateException
  3. NumberFormatException
  4. UnsupportedOperationException
Mostrar respuestaOcultar respuesta
Respuesta: A
Una capacidad negativa incumple la regla de argumentos del método, por lo que IllegalArgumentException describe el fallo. IllegalStateException describiría una llamada prohibida por el estado actual del objeto. No se menciona ninguna operación de análisis, por lo que un argumento numérico por sí solo no convierte esto en un fallo de formato numérico.

Pregunta 8 de 10

Un programa se inicia con el directorio de trabajo /work/app. Crea Path.of("data", "levels.txt"). ¿Qué ubicación absoluta identifica esa ruta relativa?
  1. /work/data/levels.txt
  2. /data/levels.txt
  3. /work/app/src/data/levels.txt
  4. /work/app/data/levels.txt
Mostrar respuestaOcultar respuesta
Respuesta: D
Una ruta relativa comienza en el directorio de trabajo, por lo que los dos elementos de la ruta amplían /work/app hasta /work/app/data/levels.txt. Java no inserta una carpeta de código fuente. Colocar el archivo junto al código fuente solo funcionaría si esa fuera casualmente la ubicación que nombra la ruta resuelta.

Pregunta 9 de 10

El recurso a se abre, pero la apertura del recurso b lanza una excepción. Ambos se declaran en la misma cabecera de try-with-resources, en ese orden. El cierre de a también lanza una excepción. ¿Qué fallo llega a quien llama?
  1. El fallo de cierre, con el de apertura suprimido.
  2. El fallo de apertura, con el de cierre descartado.
  3. El fallo de apertura, con el de cierre suprimido.
  4. Ambos fallos por separado, en el orden en que ocurrieron.
Mostrar respuestaOcultar respuesta
Respuesta: C
Cuando falla la apertura de b, Java cierra igualmente a, que ya está abierto. El fallo de apertura sigue siendo el principal y el fallo posterior de cierre se adjunta como suprimido. Elegir el fallo de cierre como principal confunde try-with-resources con la limpieza manual que puede sobrescribir un fallo anterior.

Pregunta 10 de 10

Un archivo de registro UTF-8 puede existir ya o no existir. ¿Qué opciones permiten que Files.writeString conserve el texto existente y añada texto nuevo al final?
  1. CREATE y TRUNCATE_EXISTING
  2. CREATE y APPEND
  3. APPEND sin CREATE
  4. CREATE_NEW y WRITE
Mostrar respuestaOcultar respuesta
Respuesta: B
APPEND escribe después del contenido existente y CREATE permite crear un archivo inexistente. Usar solo APPEND falla cuando el archivo de registro no existe. TRUNCATE_EXISTING borraría el contenido existente, mientras que CREATE_NEW rechaza una ruta que ya existe.
Set 2: Aplica contratos a registros y salida de archivos10 Preguntas de Práctica

Guarda esta unidad para ver todas las respuestas y practicar cada set.

Pregunta 1 de 10

Una traza comienza con estos marcos. ¿Qué línea de tu clase debes inspeccionar primero?

java.lang.NumberFormatException: For input string: "six"
    at java.base/java.lang.NumberFormatException.forInputString(...)
    at java.base/java.lang.Integer.parseInt(...)
    at Importer.readCount(Importer.java:18)
    at Importer.main(Importer.java:6)
  1. La línea 6 de Importer.main.
  2. El marco de la biblioteca en forInputString.
  3. La línea 18 de Importer.readCount.
  4. La línea posterior a la 18 en Importer.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 2 de 10

AmountProblem extiende IllegalArgumentException. ¿Cómo se clasifica?
  1. No comprobada, por RuntimeException.
  2. Comprobada, porque es una clase personalizada.
  3. Comprobada, porque su clase padre es una excepción.
  4. No comprobada, por la rama de Error.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 3 de 10

Un bucle de reintento captura InputMismatchException de Scanner.nextInt(), imprime un mensaje y llama de inmediato otra vez a nextInt(). La siguiente unidad de entrada es «many». ¿Por qué sigue fallando el bucle?
  1. El manejador rebobina todo el flujo de entrada.
  2. El scanner convierte la unidad de entrada en cero.
  3. La excepción cierra el scanner de forma permanente.
  4. La lectura fallida deja la misma unidad sin leer.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 4 de 10

Una interfaz declara void load() throws IOException. Una implementación necesita declarar un fallo de archivo inexistente. ¿Qué declaración comprobada se permite en el método que sobrescribe el heredado?
  1. throws Exception
  2. throws NoSuchFileException
  3. throws Throwable
  4. throws InterruptedException
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 5 de 10

Un inventario contiene 17 marcadores. Su método remove rechaza las solicitudes mayores que las existencias actuales antes de cambiar el mapa. Las llamadas retiran 6 y después solicitan 14; el segundo fallo se envuelve conservando su causa y lo captura quien llama. ¿Qué existencias e información de diagnóstico quedan?
  1. 11 marcadores, pero solo el mensaje nuevo de la excepción envoltorio.
  2. -3 marcadores y el fallo original como causa.
  3. 11 marcadores y el fallo original como causa.
  4. 17 marcadores y el fallo original como causa.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 6 de 10

¿Qué ocurre cuando Double.parseDouble("6,25") se ejecuta en un equipo con configuración regional alemana?
  1. Devuelve el valor decimal 6,25.
  2. Devuelve el valor entero 625.
  3. Lanza MalformedInputException.
  4. Lanza NumberFormatException.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 7 de 10

¿Qué interfaz debe implementar un objeto para declararse como recurso de try-with-resources?
  1. AutoCloseable
  2. Serializable
  3. Iterable
  4. Comparable
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 8 de 10

La línea es «Nora,». ¿Qué diferencia importa entre line.split(",") y line.split(",", -1)?
  1. Ambos devuelven dos campos con el segundo vacío.
  2. El primero conserva la coma; el segundo la elimina.
  3. El primero devuelve un campo; el segundo conserva un segundo campo vacío.
  4. El primero lanza una excepción; el segundo devuelve un campo.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 9 de 10

Un programa escribe mediante PrintWriter, pero un disco lleno impide guardar el texto. ¿Qué debe usar para detectar el error registrado por el escritor?
  1. Capturar IOException del propio println.
  2. Llamar a checkError() e inspeccionar el resultado.
  3. Inspeccionar getFileName() de la ruta del archivo.
  4. Suponer que el cierre garantiza un guardado correcto.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 10 de 10

Un informe debe proteger un resultado existente frente a una sustitución parcial. La lectura y el cálculo han terminado. ¿Qué política de guardado es adecuada?
  1. Escribir directamente en el destino; reintentar desde el principio si falla la primera escritura.
  2. Escribir un archivo temporal; usar un movimiento no atómico si falla el movimiento atómico.
  3. Comprobar que existe el destino; añadir el informe nuevo después del resultado anterior.
  4. Escribir y cerrar un archivo temporal en la misma carpeta; solicitar un movimiento atómico e informar si no se admite la sustitución.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Set 3: Sigue fallos que interactúan y la limpieza10 Preguntas de Práctica

Guarda esta unidad para ver todas las respuestas y practicar cada set.

Pregunta 1 de 10

¿Qué familia de excepciones también recibe NumberFormatException cuando la captura un manejador de superclase?
  1. RuntimeException
  2. IOException
  3. Error
  4. FileNotFoundException
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 2 de 10

¿Qué valor se imprime?

int count;
try {
    count = Integer.parseInt("bad");
} catch (NumberFormatException e) {
    count = 4;
}
System.out.println(count + 2);
  1. 4
  2. 2
  3. 6
  4. Nada; count no está inicializada.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 3 de 10

¿Qué valor llega a la impresión final?

int total = 0;
try {
    for (String text : new String[] {"8", "bad", "3"}) {
        try {
            total += Integer.parseInt(text);
        } catch (NumberFormatException e) {
            throw new IllegalStateException("record", e);
        }
    }
} catch (IllegalStateException e) {
    total += 2;
}
System.out.println(total);
  1. 13
  2. 10
  3. 11
  4. 2
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 4 de 10

¿Qué hace result()?

static int result() {
    try {
        throw new IllegalArgumentException("bad");
    } finally {
        return 9;
    }
}
  1. Lanza la excepción y nunca devuelve 9.
  2. Devuelve 9 y después lanza la excepción a quien llamó.
  3. No compila porque finally no puede retornar.
  4. Devuelve 9 y descarta la excepción pendiente.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 5 de 10

Un analizador captura NumberFormatException e. Su InvalidRecordException personalizada tiene constructores que reciben solo un mensaje y que reciben un mensaje más una causa. ¿Cómo debe añadir «Line 8» conservando la traza original?
  1. throw new InvalidRecordException(e.getMessage());
  2. throw new InvalidRecordException("Line 8", e);
  3. throw new InvalidRecordException("Line 8");
  4. throw new RuntimeException("Line 8");
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 6 de 10

Un archivo de texto de Windows contiene líneas de enteros terminadas en CRLF. El código usa Files.readString(path).split("\n") y después Integer.parseInt en cada fragmento no vacío. ¿Por qué puede fallar la conversión de un fragmento que contiene los dígitos «27»?
  1. parseInt siempre requiere un punto decimal.
  2. UTF-8 no puede representar los fines de línea de Windows.
  3. La división puede dejar un \r al final del fragmento.
  4. La división convierte automáticamente los dígitos en bytes.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 7 de 10

Los recursos a y b se abren correctamente en ese orden. El cuerpo lanza E; el cierre de b lanza F; el cierre de a lanza G. ¿Qué llega al catch asociado a esa sentencia try-with-resources?
  1. E, con F y después G como fallos suprimidos.
  2. G, con E y después F como fallos suprimidos.
  3. F, con G y después E como fallos suprimidos.
  4. E sola porque el cierre se detiene después de F.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 8 de 10

Un archivo pequeño comienza con «name,age», seguido de «Omar,36». ¿Por qué debe manejarse la primera línea por separado antes de convertir el campo de edad?
  1. Usa una codificación de caracteres distinta de la de los datos.
  2. Su coma impide que split encuentre dos campos.
  3. Un lector la devuelve automáticamente como línea vacía.
  4. Nombra las columnas en vez de proporcionar una edad entera.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 9 de 10

Un procesador lee «zone,temperature» como encabezado y después «north,2.0», «east,bad» y «west,8.0». La política requerida es omitir los registros incorrectos y guardar un informe de los válidos. Actualmente un catch rodea todo el bucle de análisis. ¿Qué cambio cumple la política?
  1. Mantener el catch fuera; reanudar el bucle automáticamente después del manejador.
  2. Escribir cada total en el destino antes de intentar analizar el siguiente registro.
  3. Capturar los fallos de registros en cada iteración; guardar solo después de terminar la lectura y el cálculo.
  4. Devolver un resultado vacío desde el lector siempre que falle el análisis.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 10 de 10

La entrada se comprueba con Files.exists y después se lee con un scanner. Su bucle termina después de solo algunos registros porque falló el lector subyacente y el programa comienza a guardar inmediatamente. ¿Qué debe cambiar para evitar que esta entrada parcial se trate como correcta?
  1. Comprobar ioException() después de leer con el scanner y detener el guardado si se registró un fallo de lectura.
  2. Repetir Files.exists después de leer con el scanner y guardar siempre que devuelva true.
  3. Capturar solo NumberFormatException alrededor de cada lectura y después guardar.
  4. Cerrar el scanner y suponer que sus lecturas anteriores completaron el archivo.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Set 4: Diagnostica y mejora un procesador completo10 Preguntas de Práctica

Guarda esta unidad para ver todas las respuestas y practicar cada set.

Pregunta 1 de 10

¿Qué se imprime antes de que la excepción salga de main y qué marco de la aplicación aparece primero en su traza?

public class Counter {
    static int read() {
        return Integer.parseInt("9z");
    }
    static void show() {
        System.out.print("L");
        System.out.print(read());
        System.out.print("M");
    }
    public static void main(String[] args) {
        show();
        System.out.print("N");
    }
}
  1. LM; Counter.show(Counter.java:7).
  2. Solo L; Counter.main(Counter.java:11).
  3. LMN; Counter.read(Counter.java:3).
  4. Solo L; Counter.read(Counter.java:3).
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 2 de 10

Un bloque catch informa de una entrada numérica no válida, pero continúa con un valor predeterminado asignado previamente. ¿Qué debe cumplirse para que ese valor permita una recuperación útil?
  1. Debe ser siempre el valor entero cero.
  2. Debe ser un valor válido para el cálculo restante.
  3. Debe ser igual al texto cuya conversión falló.
  4. Debe asignarse dentro de la sentencia fallida.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 3 de 10

Un analizador usa catch (NumberFormatException | IllegalArgumentException e). ¿Por qué esta captura múltiple no compila?
  1. Ninguna alternativa es una excepción comprobada.
  2. Las alternativas requieren dos nombres de variable distintos.
  3. Una alternativa es una subclase de la otra.
  4. La captura múltiple solo permite fallos relacionados con archivos.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 4 de 10

¿Qué imprime y qué devuelve choose()?

static int choose() {
    int value = 5;
    try {
        return value;
    } finally {
        value = 12;
        System.out.print(value);
    }
}
  1. Imprime 12 y devuelve 5.
  2. Imprime 12 y devuelve 12.
  3. Imprime 5 y devuelve 5.
  4. No imprime nada y devuelve 12.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 5 de 10

La interfaz ReaderTask declara String read() throws IOException. La clase FixedTask la implementa con public String read() y sin una declaración comprobada. La variable task tiene tipo ReaderTask y hace referencia a un FixedTask. ¿Qué debe hacer el código que llama a task.read()?
  1. Omitir el manejo porque la implementación no declara ningún fallo comprobado.
  2. Capturar RuntimeException en lugar del tipo comprobado declarado.
  3. Añadir throws IOException a la implementación antes de llamarla.
  4. Capturar o declarar IOException según la declaración de la interfaz.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 6 de 10

Un método que sobrescribe otro no puede añadir excepciones comprobadas, pero llama a código de archivos que puede lanzar IOException. ¿Qué clase envoltorio estándar conserva esa causa y presenta un fallo no comprobado?
  1. new IOException(e.getMessage())
  2. new UncheckedIOException(e)
  3. new Exception(e)
  4. new RuntimeException("error")
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 7 de 10

El cuerpo de una sentencia con recursos devuelve 6. Después, su close() lanza IOException y el catch asociado devuelve 2; su bloque finally imprime «closed» sin lanzar una excepción. ¿Qué hace el método?
  1. Imprime closed y devuelve 2.
  2. Imprime closed y devuelve 6.
  3. Lanza IOException y no devuelve ningún valor.
  4. Devuelve 6 sin entrar en el catch.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 8 de 10

Un archivo tiene el encabezado «label,count» y después «oak,7», «ash,», «elm,11» y «fir,x». El procesador omite el encabezado, conserva los campos vacíos al dividir, valida ambos campos y captura los fallos de registros dentro del bucle. ¿Qué recuento válido, suma y números de líneas físicas rechazadas resultan?
  1. 3 registros, suma 18; se rechaza solo la línea 5.
  2. 1 registro, suma 7; se rechazan las líneas 3, 4 y 5.
  3. 2 registros, suma 18; se rechazan las líneas 3 y 5.
  4. 2 registros, suma 18; se rechazan las líneas 2 y 4.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 9 de 10

Un archivo de datos UTF-8 debe contener una línea «sample,7.50», cuyo segundo campo pueda leerse con Double.parseDouble en equipos con cualquier configuración regional. ¿Qué forma de escritura cumple ese formato?
  1. Escribir "sample," + String.format("%.2f", 7.5) y un fin de línea.
  2. Escribir "sample," + String.format(Locale.ROOT, "%.2f", 7.5) y un fin de línea.
  3. Escribir "sample," + String.format(Locale.GERMANY, "%.2f", 7.5) y un fin de línea.
  4. Escribir "sample," + Integer.toString((int) 7.5) y un fin de línea.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

Pregunta 10 de 10

Un procesador lee un encabezado válido y tres registros no válidos. Debe informar de los datos aceptados y los registros omitidos, y proteger un informe existente frente a una sustitución parcial. ¿Qué resultado y secuencia de guardado son adecuados?
  1. Informar de ninguna lectura válida y tres omisiones; mover la salida temporal al destino antes de cerrar su escritor.
  2. Informar de ninguna lectura válida y cuatro omisiones; cerrar la salida temporal y solicitar una sustitución atómica.
  3. Informar de ninguna lectura válida y tres omisiones; sustituir directamente el destino, y después vaciar y cerrar su escritor.
  4. Informar de ninguna lectura válida y tres omisiones; cerrar la salida temporal y solicitar una sustitución atómica.
Mostrar respuestaOcultar respuesta

Guarda esta unidad para ver esta respuesta.

¿Te atascas con una pregunta tuya? Ayuda con Tareas

Términos Clave

64 Términos Clave, cada uno con su definición

A

Análisis sintáctico
El análisis sintáctico interpreta texto según una estructura esperada y convierte los campos en valores u objetos que el programa puede usar.
El análisis de un registro de nombre y edad comprueba sus dos campos antes de convertir la edad y construir una persona.
Archivo temporal
Un archivo temporal guarda una salida intermedia separada del destino final para que pueda completarse antes de intentar una sustitución.
Un archivo temporal para un informe se crea en la carpeta de destino antes de mover el texto completo a su ubicación final.

B

Bloque finally
Un bloque finally es código de limpieza que se ejecuta cuando el control sale de su sentencia try, incluso después del trabajo normal, un manejador, un retorno o una excepción lanzada.
El bloque finally imprime un mensaje de limpieza antes de que un valor preparado por return llegue a quien llamó.
Bloque try
Un bloque try contiene trabajo cuyas excepciones pueden manejar las cláusulas catch asociadas; sus sentencias restantes se omiten si ocurre un fallo.
Un bloque try que convierte texto en un entero y luego lo imprime se detiene antes de la sentencia de impresión cuando la conversión falla.
Búfer
Un búfer es una zona de memoria que mantiene temporalmente texto antes de enviarlo a un archivo, lo que reduce el número de pequeñas operaciones de salida.
El búfer de un escritor puede seguir guardando la última línea del informe hasta que se vacíe o se cierre el escritor.

C

Campo de datos
Un campo de datos es un valor dentro de un registro estructurado, como el nombre o la edad separados por una coma en una línea sencilla de datos de texto.
El segundo campo de «Mina,» está vacío cuando se divide con un límite negativo que conserva los campos vacíos finales.
Captura múltiple
Una captura múltiple es una cláusula catch que une tipos de excepciones no relacionados con una barra vertical para que compartan el mismo cuerpo de manejador.
Una captura múltiple puede informar de un registro mal formado tanto por un campo entero incorrecto como por un elemento de arreglo ausente.
Causa
Una causa es el objeto lanzable original conservado dentro de una excepción envoltorio y disponible mediante getCause para el diagnóstico.
La causa de una InvalidRecordException puede ser la NumberFormatException producida por su campo numérico.
Clase BufferedReader
Un BufferedReader lee eficientemente la entrada de caracteres mediante un búfer y puede devolver una línea cada vez sin su fin de línea.
Un bucle con BufferedReader procesa una entrada grande hasta que readLine() devuelve null al final.
Clase BufferedWriter
Un BufferedWriter escribe salida de caracteres mediante un búfer, ofrece soporte para fines de línea e informa de los fallos de entrada y salida con IOException.
Un BufferedWriter escribe una línea de informe y después usa newLine() para añadir el fin de línea de la plataforma.
Clase Error
Un Error es un subtipo de Throwable para fallos graves de ejecución o del entorno que la recuperación normal de una aplicación no debería intentar capturar.
OutOfMemoryError pertenece a Error; capturar una entrada no válida normal no resuelve el agotamiento de la memoria dinámica.
Clase PrintWriter
Un PrintWriter escribe salida de caracteres formateada con métodos de impresión que registran internamente los fallos de entrada y salida para que checkError informe de ellos.
Un PrintWriter puede dar formato a una media con printf, pero que esa llamada termine correctamente no demuestra que el guardado haya tenido éxito.
Clase RuntimeException
RuntimeException es la subclase de Exception cuyos descendientes representan fallos no comprobados, incluidos los argumentos no válidos y el uso de referencias nulas.
NumberFormatException llega a RuntimeException a través de su superclase IllegalArgumentException.
Clase Scanner
Un Scanner lee texto como unidades de entrada o líneas y ofrece métodos de conversión, a la vez que registra los fallos subyacentes de lectura de entrada y salida para su inspección posterior.
Un Scanner de archivo necesita una comprobación de ioException() después de su bucle para que una lectura fallida no parezca correcta.
Clase Throwable
Throwable es la superclase de Java de los objetos que pueden lanzarse y tiene Error y Exception como sus dos subclases directas principales.
Una excepción comprobada personalizada pertenece a Throwable a través de Exception, por lo que Java puede lanzarla y capturarla.
Cláusula catch
Una cláusula catch indica un tipo que puede lanzarse y un manejador que se ejecuta cuando una excepción del trabajo protegido coincide con ese tipo.
Una cláusula catch para NumberFormatException puede pedir otro número después de que el usuario escriba «many».
Cláusula throws
Una cláusula throws es parte de la declaración de un método que enumera los tipos de excepciones que pueden salir de él y pasa a quienes llaman las obligaciones de manejo de las comprobadas.
La cláusula throws throws IOException permite que un método auxiliar de archivos informe del fallo a quien llama y puede recuperarse.
Codificación de caracteres
Una codificación de caracteres relaciona los caracteres de texto con los bytes almacenados y especifica cómo un lector interpreta esos bytes para recuperar el texto.
Una codificación de caracteres incorrecta puede mostrar el texto UTF-8 «café» como texto corrupto, por ejemplo «café».
Configuración regional
Una configuración regional proporciona convenciones de idioma y formato regional que pueden afectar al análisis de números de Scanner y a la salida decimal formateada.
Seleccionar la configuración regional raíz hace que los datos decimales formateados usen «3.50» independientemente de la configuración del equipo.

D

Directorio de trabajo
El directorio de trabajo es la carpeta actual del programa que sirve de punto de partida para las rutas relativas y que puede ser distinta de la carpeta del código fuente.
Con /work/app como directorio de trabajo, data/counts.txt apunta dentro de /work/app/data.

E

Encadenamiento de excepciones
El encadenamiento de excepciones conserva una excepción original como causa de una nueva excepción que añade un tipo o un contexto de diagnóstico más útil.
El encadenamiento de excepciones añade el número de línea del registro fallido sin perder la traza de conversión original.
Enmascaramiento de excepciones
El enmascaramiento de excepciones ocurre cuando una transferencia de control posterior sustituye un fallo anterior y oculta la excepción original a quien llamó.
Un retorno en finally puede causar enmascaramiento de excepciones al descartar un fallo producido en el bloque try.
Escritura al final del archivo
La escritura al final del archivo añade nueva salida al final de un archivo existente y conserva los caracteres que ya están almacenados allí.
Añadir una entrada al final de un registro conserva las entradas anteriores, pero no inserta un separador ausente antes del texto nuevo.
Excepción
Una excepción es un objeto que describe un suceso que interrumpe un programa en ejecución y transfiere el control hacia un manejador que coincida.
Una excepción al analizar «red» detiene la asignación antes de que el programa pueda usar su resultado numérico.
Excepción ArithmeticException
Una ArithmeticException es una excepción no comprobada que indica una condición aritmética excepcional, como la división entera entre cero.
Calcular una media entera con un arreglo vacío puede lanzar ArithmeticException en la división.
Excepción comprobada
Una excepción comprobada es un subtipo de Throwable fuera de las ramas de RuntimeException y Error que requiere manejarse mediante la regla de capturar o declarar.
Una IOException es una excepción comprobada, por lo que un método auxiliar de lectura de archivos debe capturarla o declararla.
Excepción IllegalArgumentException
Una IllegalArgumentException es una excepción no comprobada que se usa cuando quien llama proporciona un valor que incumple los requisitos de argumentos de un método.
Un método puede lanzar IllegalArgumentException cuando la cantidad positiva requerida se proporciona como -2.
Excepción IllegalStateException
Una IllegalStateException es una excepción no comprobada que se usa cuando el estado actual de un objeto no permite la operación solicitada.
Un pedido ya enviado puede lanzar IllegalStateException cuando el código intenta añadirle otro artículo.
Excepción InputMismatchException
Una InputMismatchException es un fallo no comprobado de Scanner que ocurre cuando una unidad de entrada no se ajusta al tipo o al rango solicitado por un método de conversión.
nextInt() lanza InputMismatchException con «several» y deja esa unidad de entrada disponible para descartarla.
Excepción no comprobada
Una excepción no comprobada pertenece a RuntimeException o Error, o a una subclase de cualquiera de ellas, y no tiene una exigencia obligatoria de capturar o declarar.
Un índice de arreglo incorrecto causa una excepción no comprobada incluso cuando el programa se ha compilado correctamente.
Excepción NullPointerException
Una NullPointerException es una excepción no comprobada que se produce cuando una operación requiere un objeto pero recibe o usa una referencia nula.
Llamar a name.trim() cuando name es null lanza NullPointerException antes de devolver cualquier texto sin espacios alrededor.
Excepción NumberFormatException
Una NumberFormatException es una excepción no comprobada que se produce cuando una conversión de texto numérico no puede obtener el valor numérico solicitado.
Integer.parseInt("blue") lanza NumberFormatException porque el texto no puede representar un entero.
Excepción personalizada
Una excepción personalizada es una clase definida por la aplicación cuyos objetos pueden lanzarse y que permite reconocer y manejar un fallo significativo del dominio.
Un inventario usa una excepción personalizada para distinguir las existencias insuficientes de un argumento no válido.
Excepción suprimida
Una excepción suprimida es un fallo adicional adjunto a una excepción principal, como un fallo de cierre después de que el cuerpo de una sentencia con recursos ya haya lanzado una excepción.
La excepción suprimida conserva el fallo de cierre de un lector mientras se propaga el fallo original de análisis.
Excepción UncheckedIOException
Una UncheckedIOException es una subclase estándar de RuntimeException que envuelve una IOException y conserva el fallo de archivo original como causa.
Un método que sobrescribe otro y no puede declarar IOException puede propagar un fallo de archivo mediante UncheckedIOException.

F

Fallo de un registro
Un fallo de un registro hace inutilizable un registro de entrada mientras permite procesar los posteriores según una política de omitir e informar.
Un fallo de un registro informa «Line 6: invalid temperature» y deja alcanzable la siguiente iteración.
Fallo del archivo completo
Un fallo del archivo completo impide que una operación de archivo termine de forma fiable, como una entrada inexistente o un error de disco al guardar un informe.
Un fallo del archivo completo durante la lectura debe detener el guardado para que una entrada incompleta no se notifique como resultado completo.
Fallo inmediato
El fallo inmediato consiste en rechazar una entrada o un estado no válidos en el punto donde se detectan, antes de que el trabajo posterior pueda extender u ocultar el problema.
El fallo inmediato en un método modificador comprueba un porcentaje no válido antes de asignar nada al campo.
Fila de encabezados
Una fila de encabezados nombra las columnas de un archivo de datos y se maneja por separado para que sus etiquetas no se analicen como valores normales de registros.
La fila de encabezados «name,age» debe omitirse o comprobarse antes de que el analizador intente convertir una edad.
Fin de línea
Un fin de línea es la secuencia de caracteres que termina una línea de texto, normalmente LF en Linux y macOS o CRLF en Windows.
Un fin de línea leído por BufferedReader.readLine() se elimina antes de que el método devuelva el texto de la línea.

I

Interfaz AutoCloseable
AutoCloseable es la interfaz que declara close y permite que un objeto se cierre automáticamente mediante una sentencia try con recursos.
Una clase auxiliar que implementa AutoCloseable puede imprimir su nombre cuando la limpieza automática llama a close().
Interfaz Closeable
Closeable es una subinterfaz de AutoCloseable para recursos de entrada y salida cuyo método close declara IOException en lugar de la Exception más general.
Un BufferedReader implementa Closeable, por lo que cumple el requisito para una declaración en try-with-resources.
Interfaz Path
Un Path es un objeto que representa una ubicación en un sistema de archivos; construirlo no abre, crea ni comprueba el archivo indicado.
Path.of("data", "counts.txt") construye un Path sin comprobar si existe la carpeta de datos.

J

Jerarquía de excepciones
Una jerarquía de excepciones es una estructura de herencia que permite capturar un fallo específico o una superclase común de fallos relacionados.
Una jerarquía de excepciones puede situar los fallos por artículo desconocido y existencias insuficientes bajo un mismo tipo base de inventario.

L

Limpieza
La limpieza es el trabajo que libera recursos o restaura una configuración cuando termina una operación, incluidas las rutas que salen debido a un fallo.
La limpieza cierra un archivo abierto incluso cuando el análisis de uno de sus registros lanza una excepción.

M

Manejador de excepciones inalcanzable
Un manejador de excepciones inalcanzable es una cláusula catch que no puede recibir una excepción porque un manejador anterior ya cubre todos los tipos que coinciden.
Colocar IOException primero crea un manejador inalcanzable si después se captura NoSuchFileException.
Movimiento atómico
Un movimiento atómico cambia la ubicación de un archivo como una sola operación del sistema de archivos cuando se admite; la sustitución de un destino existente depende de la implementación.
Un movimiento atómico publica un informe completo de una vez y, si no se admite la sustitución, se informa de un fallo de guardado.

O

Orden de captura
El orden de captura es la secuencia de arriba abajo en la que se comprueban los manejadores, que exige que uno de subclase preceda a uno de superclase.
El orden de captura coloca NoSuchFileException antes de IOException cuando cada una necesita un mensaje distinto.

P

Palabra clave throw
La palabra clave throw inicia una sentencia que envía un objeto de excepción fuera de la operación actual e interrumpe su ejecución normal.
Un throw antes de la asignación de un campo rechaza una capacidad no válida y conserva el valor anterior del campo.
Pila de llamadas
La pila de llamadas es la cadena de llamadas a métodos actualmente activas en un hilo, donde cada llamada espera el trabajo que solicitó.
Cuando main llama a load, que llama a parse, la pila de llamadas registra las tres llamadas a métodos activas.
Propagación
La propagación es el paso de una excepción sin manejar hacia fuera por el código que la contiene y los métodos que llamaron, hasta encontrar un manejador.
La propagación lleva una lectura fallida fuera de un método auxiliar de lectura de archivos hasta un llamador que puede pedir otro archivo.

R

Recuperación
La recuperación es la respuesta del programa que le permite continuar de forma útil después de un fallo, por ejemplo al reintentar u omitir un registro incorrecto.
La recuperación en un bucle de entrada lee una línea nueva antes de intentar otra conversión, para poder avanzar.
Recurso
Un recurso es un objeto que mantiene un elemento externo, como un archivo abierto, que debe liberarse después de terminar su uso.
Un lector de archivos es un recurso que debe cerrarse incluso cuando falla el procesamiento de su siguiente línea.
Región protegida
Una región protegida es el trabajo contenido en una sentencia try; su límite determina qué se abandona cuando un fallo llega a su manejador.
La región protegida cubre un registro cuando una sentencia try de conversión está dentro del cuerpo del bucle.
Regla de capturar o declarar
La regla de capturar o declarar exige que el código que puede lanzar una excepción comprobada la maneje o incluya un tipo aplicable en la declaración de su método.
La regla de capturar o declarar se aplica a un método que llama a Files.readString, incluso cuando existe el archivo que lee.
Retorno pendiente
Un retorno pendiente es un retorno cuya expresión ya se ha evaluado, pero cuya transferencia a quien llamó espera a que termine la limpieza requerida.
Cambiar un entero local durante finally no vuelve a evaluar la expresión de un retorno pendiente.
Ruta absoluta
Una ruta absoluta especifica una ubicación desde la raíz del sistema de archivos, incluida la raíz de una unidad cuando sea necesario, independientemente del directorio de trabajo.
Llamar a toAbsolutePath() muestra la ruta absoluta utilizada para diagnosticar un archivo colocado en la carpeta equivocada.
Ruta relativa
Una ruta relativa identifica una ubicación desde el directorio de trabajo en lugar de comenzar en la raíz del sistema de archivos o de una unidad.
La ruta relativa data/counts.txt puede identificar un archivo distinto cuando el programa se inicia en otra carpeta.

S

Sentencia try con recursos
La sentencia try con recursos es una sentencia Java que cierra automáticamente los recursos AutoCloseable abiertos correctamente cuando se sale del trabajo protegido.
La sentencia try con recursos cierra un escritor antes que el lector cuando las declaraciones de su cabecera abren primero el lector.

T

Traza de la pila
Una traza de la pila informa de una excepción y de sus llamadas a métodos activas, comenzando por el punto de detección y continuando por quienes llamaron.
Cuando un método auxiliar llamado por main falla en una conversión, la traza de la pila señala primero la conversión y después el método auxiliar y main.
Truncamiento
El truncamiento elimina el contenido de un archivo existente cuando se abre para sustituirlo, antes de que necesariamente se haya escrito correctamente la nueva salida.
Files.writeString con las opciones predeterminadas causa truncamiento, por lo que un fallo de escritura posterior puede dejar un resultado incompleto.

U

UTF-8
UTF-8 es una codificación de caracteres Unicode que usa un byte para los caracteres latinos básicos y hasta cuatro bytes para otros caracteres Unicode.
En UTF-8, «café» ocupa cinco bytes aunque solo contiene cuatro caracteres visibles.

V

Vaciado del búfer
El vaciado del búfer envía la salida que espera en el búfer de un escritor hacia su destino; por sí solo no libera el recurso abierto.
Vaciar el búfer hace que el texto pendiente salga del búfer del escritor, pero el programa aún debe cerrar su recurso de archivo.
Valores separados por comas (CSV)
CSV es texto de valores separados por comas, que normalmente almacena un registro por línea; los campos entrecomillados pueden contener comas y requieren un análisis CSV adecuado.
Un CSV sencillo que contiene «Mina,28» puede dividirse, mientras que una coma entrecomillada en un nombre necesita un analizador CSV.

Sobre esta unidad

Por StudeliInformar de un error

Crea tus propios Materiales de Estudio

Convierte tus notas, diapositivas y documentos en Guías de Estudio, Preguntas de Práctica, Flashcards y 6 herramientas más.

Comenzar