- Aprender
- Informática
- Programación
- Programación orientada a objetos con Java
- Excepciones y archivos en Java
Excepciones y archivos en Java
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
- 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 pilaExplica 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 comprobadasSitú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.
- Interpreta una excepción y su traza de la pila
- 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ónEscribe 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 adecuadoUsa 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 finallyAñ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.
- Captura una excepción y recupera la ejecución
- 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 throwsValida 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 causaEscribe 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.
- Lanza excepciones y decláralas con throws
- 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íneaConstruye 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-resourcesUsa 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.
- Trabaja con rutas, codificaciones y fines de línea
- 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 datosLee 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 finalEscribe 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 archivosCombina 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.
- Lee un archivo de texto y convierte sus líneas en datos
Guía de estudio de Excepciones y archivos en Java
1Comprende 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ón | Causa habitual |
|---|---|
ArithmeticException | División entera entre cero |
ArrayIndexOutOfBoundsException | a[3] cuando el arreglo tiene longitud 3 |
IndexOutOfBoundsException | list.get(list.size()) |
NullPointerException | Llamar a un método mediante null |
NumberFormatException | Integer.parseInt("12a") |
InputMismatchException | Scanner.nextInt() encuentra «ten» |
ClassCastException | Convertir 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)
- Lee la primera línea para conocer la clase de excepción y el mensaje.
- Lee el primer marco
atpara localizar dónde se detectó el problema. - Lee hacia abajo para identificar a quienes llamaron:
mainllamó aaverageen la línea 9. - 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ía | Clases | Exigencia del compilador |
|---|---|---|
| No comprobadas | RuntimeException, Error y sus subclases | Capturar o declarar es opcional |
| Comprobadas | Todas las demás subclases de Throwable | Capturar 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,Errory todas sus subclases son no comprobadas.- Las demás subclases de
Throwableson 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
Exceptionpuede ocultar fallos de programación. - Clasifica una excepción desconocida por su cadena de superclases.
2Maneja 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
tryque 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
finallyse ejecuta al terminar normalmente, con excepciones capturadas y no capturadas, y con transferencias de control comoreturn.- Una expresión de retorno se evalúa antes de que se ejecute la limpieza.
- El código posterior a una sentencia
tryse omite cuando se propaga una excepción; aun así se llega afinally. - Un retorno o una excepción lanzada en
finallypueden 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.
3Lanza 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.
| Problema | Excepción estándar |
|---|---|
| Un argumento tiene un valor no válido | IllegalArgumentException |
| El objeto está en un estado incorrecto para la llamada | IllegalStateException |
Una referencia a objeto requerida es null | NullPointerException |
| La clase no ofrece la operación | UnsupportedOperationException |
| La posición está fuera de una colección | IndexOutOfBoundsException |
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
throwcon un objeto de excepción para detener una operación no válida. - Valida antes de cambiar campos o colecciones.
throwsdeclara 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
Exceptionpara una clase comprobada oRuntimeExceptionpara 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.
UncheckedIOExceptiontransmite unaIOExceptioncomo fallo no comprobado.
4Localiza 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ón | Secuencia 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
Pathno 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.parseDoubleusa 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
AutoCloseablepueden 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.
5Lee 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étodo | Resultado 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
CREATEconAPPENDpara conservar el contenido anterior y permitir un registro nuevo. - El cierre vacía la salida almacenada en el búfer y libera el recurso.
PrintWriterregistra los errores de escritura;checkError()permite consultarlos.BufferedWritery los métodos deFilespropagan los fallos de entrada y salida.- Usa UTF-8 y
Locale.ROOTpara 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
1Sigue un fallo hasta su causa
11 pasos
- 1Introducció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.
- 2EjemploObserva cómo se detiene la conversión
Un método
loadCountejecuta estas sentencias:System.out.print("start "); int count = Integer.parseInt("eight"); System.out.print("finish");Imprime
starty después lanzaNumberFormatException. La asignación no se completa y se omitefinish. Un manejador que coincida puede tomar el control, pero la sentencia fallida no se reanuda después de la recuperación. - 3ExplicaciónSigue las llamadas activas
Supón que
mainllamó aloadCount, que llamó aInteger.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.parseIntfalla primero,loadCountno puede terminar su trabajo normal y quien llamó tiene la oportunidad de manejar el fallo. Si sale demainsin manejarse, Java informa de la excepción y el hilo principal termina. - 4EjemploEncuentra 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. - 5DesafíoEncuentra la salida omitida
Un método auxiliar imprime
A, llama aInteger.parseInt("q2")y después imprimiríaB. Quien lo llama capturaNumberFormatExceptione imprimeC. ¿Qué letras se imprimen y por qué?---reveal---
Ay despuésC. La conversión lanza una excepción antes deB; 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 imprimirB. - 6ConsejoBusca 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 yprintStackTrace()para la cadena de llamadas. Un mensaje puede sernull; una secciónCaused by:proporciona otra excepción conservada dentro de una excepción envoltorio. - 7ExplicaciónUsa la cadena de superclases
Throwablees la clase base de los objetos que pueden lanzarse. Sus ramas principales sonErroryException;RuntimeExceptionse encuentra bajoException.RuntimeException,Errory todas las subclases de cualquiera de ellas son no comprobadas. Las demás subclases deThrowableson 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. - 8EjemploCompara un analizador y un lector de archivos
NumberFormatExceptionextiendeIllegalArgumentExceptiony esta extiendeRuntimeException, por lo que una llamada aInteger.parseIntno tiene un manejador obligatorio.IOExceptionextiendeExceptionfuera de esa rama. Una llamada aFiles.readStringdebe capturar su posibleIOExceptiono declararla conthrows. Un archivo puede fallar por causas externas aunque el código que llama sea correcto. - 9DesafíoClasifica un fallo desconocido
BadRecordExceptionextiendeExceptiondirectamente. 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.
- 10DesafíoExplica un manejador sorprendentemente general
Un bloque de lectura de archivos captura
Exceptione imprime «Problema de archivo». En cambio, falla con unaNullPointerExceptioncausada por un error. ¿La recibirá el manejador y es fiable ese mensaje?---reveal---
Sí:
NullPointerExceptionextiendeRuntimeException, que extiendeException. 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. - 11RepasoElige 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.
2Sigue las rutas de recuperación y limpieza
12 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónDecide qué debe ocurrir después
- 2EjemploRecupera la ejecución después de toda la sentencia
- 3ConsejoHaz que un reintento lea texto nuevo
- 4DesafíoCorrige el scanner atascado
- 5ExplicaciónDa una respuesta propia a un fallo específico
- 6EjemploDeja que el bucle continúe
- 7DesafíoMueve el límite protegido
- 8Idea claveComparte respuestas sin tipos que se solapen
- 9ExplicaciónLa limpieza se ejecuta antes de salir
- 10DesafíoSigue un fallo que no coincide
- 11DesafíoEvita que la limpieza oculte un fallo que debe reintentarse
- 12RepasoSigue la siguiente sentencia alcanzable
3Rechaza una solicitud sin dañar el estado
11 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónConserva un objeto utilizable
- 2EjemploValida antes de restar
- 3ExplicaciónDistingue el lanzamiento de la declaración
- 4DesafíoElige el fallo estándar adecuado
- 5ConexiónUn método sobrescrito mantiene las promesas a quienes llaman
- 6EjemploDa un tipo propio a las existencias insuficientes
- 7EjemploMantén separada la solicitud fallida
- 8DesafíoDecide qué estado se conserva
- 9ExplicaciónConserva el fallo de conversión original
- 10DesafíoTransmite un fallo de archivo mediante un método restringido
- 11RepasoDiseña una excepción que quien llama pueda usar
4Abre el texto correcto y ciérralo de forma segura
12 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónLa ubicación y el tiempo de vida importan
- 2EjemploResuelve desde el directorio de trabajo
- 3ExplicaciónDecodifica con la codificación utilizada al escribir
- 4ConsejoElimina un fin de línea completo
- 5DesafíoHaz que un decimal pueda escribirse y volver a leerse
- 6ExplicaciónDeclara un recurso para cerrarlo
- 7ConexiónUsa el contrato de cierre
- 8EjemploInvierte el orden de apertura
- 9DesafíoSigue una segunda apertura fallida
- 10Idea claveMantén un fallo del cuerpo como informe principal
- 11DesafíoDistingue el fallo de datos del fallo de limpieza
- 12RepasoInspecciona una operación de archivo en orden
5Convierte lecturas en un informe fiable
16 pasos
Guarda esta unidad para seguir cada Lección Interactiva paso a paso.
- 1IntroducciónUn informe necesita más que una aritmética correcta
- 2ExplicaciónElige cómo llegan las líneas
- 3EjemploDefine el registro antes de analizarlo
- 4EjemploValida antes de usar el segundo campo
- 5DesafíoLocaliza el registro rechazado
- 6ExplicaciónElige entre sustituir o añadir al final
- 7EjemploEscribe una línea de informe portátil
- 8ConsejoDetecta una escritura fallida
- 9DesafíoConserva las entradas antiguas y nuevas del registro
- 10ConexiónRecupera la ejecución en dos niveles distintos
- 11EjemploActualiza los totales solo después de validar
- 12DesafíoManeja un valor que se analiza pero no sirve
- 13ExplicaciónTermina la salida antes de sustituir el destino
- 14ConsejoMantén visible el fallo de guardado
- 15DesafíoElige qué puede notificarse con seguridad
- 16RepasoRevisa el procesador según la ruta de fallo
Ejercicios de Excepciones y archivos en Java
Set 1: Sigue los fallos y elige una recuperación útil10 Preguntas de Práctica
Pregunta 1 de 10
BufferedReader ha llegado al final de su archivo. ¿Qué devuelve la siguiente llamada a readLine()?Mostrar respuestaOcultar respuesta
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
values[5]?Mostrar respuestaOcultar respuesta
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?Mostrar respuestaOcultar respuesta
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");
Mostrar respuestaOcultar respuesta
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
NoSuchFileException u otra IOException. ¿Qué orden de captura da a cada una su propia respuesta?Mostrar respuestaOcultar respuesta
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");
}
}
Mostrar respuestaOcultar respuesta
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
Mostrar respuestaOcultar respuesta
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
/work/app. Crea Path.of("data", "levels.txt"). ¿Qué ubicación absoluta identifica esa ruta relativa?Mostrar respuestaOcultar respuesta
/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
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?Mostrar respuestaOcultar respuesta
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
Files.writeString conserve el texto existente y añada texto nuevo al final?Mostrar respuestaOcultar respuesta
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)
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 2 de 10
AmountProblem extiende IllegalArgumentException. ¿Cómo se clasifica?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 3 de 10
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?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 4 de 10
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?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 5 de 10
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?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 6 de 10
Double.parseDouble("6,25") se ejecuta en un equipo con configuración regional alemana?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 7 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 8 de 10
line.split(",") y line.split(",", -1)?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 9 de 10
PrintWriter, pero un disco lleno impide guardar el texto. ¿Qué debe usar para detectar el error registrado por el escritor?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 10 de 10
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
NumberFormatException cuando la captura un manejador de superclase?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);
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);
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;
}
}
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 5 de 10
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?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 6 de 10
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»?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 7 de 10
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?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 8 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 9 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 10 de 10
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?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");
}
}
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 2 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 3 de 10
catch (NumberFormatException | IllegalArgumentException e). ¿Por qué esta captura múltiple no compila?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);
}
}
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 5 de 10
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()?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 6 de 10
IOException. ¿Qué clase envoltorio estándar conserva esa causa y presenta un fallo no comprobado?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 7 de 10
close() lanza IOException y el catch asociado devuelve 2; su bloque finally imprime «closed» sin lanzar una excepción. ¿Qué hace el método?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 8 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 9 de 10
Double.parseDouble en equipos con cualquier configuración regional. ¿Qué forma de escritura cumple ese formato?Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
Pregunta 10 de 10
Mostrar respuestaOcultar respuesta
Guarda esta unidad para ver esta respuesta.
¿Te atascas con una pregunta tuya? Ayuda con Tareas
Términos Clave
A
Análisis sintáctico
Archivo temporal
B
Bloque finally
return llegue a quien llamó.Bloque try
Búfer
C
Campo de datos
Captura múltiple
Causa
InvalidRecordException puede ser la NumberFormatException producida por su campo numérico.Clase BufferedReader
BufferedReader procesa una entrada grande hasta que readLine() devuelve null al final.Clase BufferedWriter
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
OutOfMemoryError pertenece a Error; capturar una entrada no válida normal no resuelve el agotamiento de la memoria dinámica.Clase PrintWriter
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
NumberFormatException llega a RuntimeException a través de su superclase IllegalArgumentException.Clase Scanner
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 a través de Exception, por lo que Java puede lanzarla y capturarla.Cláusula catch
NumberFormatException puede pedir otro número después de que el usuario escriba «many».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
Configuración regional
D
Directorio de trabajo
/work/app como directorio de trabajo, data/counts.txt apunta dentro de /work/app/data.E
Encadenamiento de excepciones
Enmascaramiento de excepciones
finally puede causar enmascaramiento de excepciones al descartar un fallo producido en el bloque try.Escritura al final del archivo
Excepción
Excepción ArithmeticException
ArithmeticException en la división.Excepción comprobada
IOException es una excepción comprobada, por lo que un método auxiliar de lectura de archivos debe capturarla o declararla.Excepción IllegalArgumentException
IllegalArgumentException cuando la cantidad positiva requerida se proporciona como -2.Excepción IllegalStateException
IllegalStateException cuando el código intenta añadirle otro artículo.Excepción InputMismatchException
nextInt() lanza InputMismatchException con «several» y deja esa unidad de entrada disponible para descartarla.Excepción no comprobada
Excepción NullPointerException
name.trim() cuando name es null lanza NullPointerException antes de devolver cualquier texto sin espacios alrededor.Excepción NumberFormatException
Integer.parseInt("blue") lanza NumberFormatException porque el texto no puede representar un entero.Excepción personalizada
Excepción suprimida
Excepción UncheckedIOException
IOException puede propagar un fallo de archivo mediante UncheckedIOException.F
Fallo de un registro
Fallo del archivo completo
Fallo inmediato
Fila de encabezados
Fin de línea
BufferedReader.readLine() se elimina antes de que el método devuelva el texto de la línea.I
Interfaz AutoCloseable
AutoCloseable puede imprimir su nombre cuando la limpieza automática llama a close().Interfaz Closeable
BufferedReader implementa Closeable, por lo que cumple el requisito para una declaración en try-with-resources.Interfaz Path
Path.of("data", "counts.txt") construye un Path sin comprobar si existe la carpeta de datos.J
Jerarquía de excepciones
L
Limpieza
M
Manejador de excepciones inalcanzable
IOException primero crea un manejador inalcanzable si después se captura NoSuchFileException.Movimiento atómico
O
Orden de captura
NoSuchFileException antes de IOException cuando cada una necesita un mensaje distinto.P
Palabra clave throw
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
main llama a load, que llama a parse, la pila de llamadas registra las tres llamadas a métodos activas.Propagación
R
Recuperación
Recurso
Región protegida
Regla de capturar o declarar
Files.readString, incluso cuando existe el archivo que lee.Retorno pendiente
finally no vuelve a evaluar la expresión de un retorno pendiente.Ruta absoluta
toAbsolutePath() muestra la ruta absoluta utilizada para diagnosticar un archivo colocado en la carpeta equivocada.Ruta relativa
data/counts.txt puede identificar un archivo distinto cuando el programa se inicia en otra carpeta.S
Sentencia try con recursos
T
Traza de la pila
Truncamiento
Files.writeString con las opciones predeterminadas causa truncamiento, por lo que un fallo de escritura posterior puede dejar un resultado incompleto.U
UTF-8
V
Vaciado del búfer
Valores separados por comas (CSV)
- 1Primeros programas en Java
- 2Condiciones y bucles en Java
- 3Métodos en Java
- 4Listas, arreglos y cadenas en Java
- 5Clases y objetos en Java
- 6Objetos y referencias en Java
- 7HashMap y colecciones en Java
- 8Herencia, interfaces y polimorfismo en Java
- 9Excepciones y archivos en Java
- 10Paquetes en Java
- 11Genéricos y expresiones lambda en Java
Sobre esta unidad
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.