- Learn
- Computer Science & IT
- Programming
- Object-Oriented Programming with Java
- Exceptions and Files in Java
Exceptions and Files in Java
try, catch and finally. Throw your own exceptions and design exception classes that say exactly what went wrong. Then read and write text files with paths, encodings and line endings under control, close every file safely with try-with-resources, and build a program that copes with missing files and bad data.BeginnerLesson 9 of 11 in Object-Oriented Programming with Java Course
What you will learn
- Recognize an exception when a program fails, read the stack trace to find where and why it happened, and place any exception in Java's class hierarchy as checked or unchecked.
- Read an exception and its stack traceExplain what happens when a statement throws an exception, name the common runtime exceptions and their causes, and use a stack trace to locate the problem.
- Classify exceptions as checked or uncheckedPlace any exception in the hierarchy below Throwable, decide whether it is checked or unchecked, and apply the rule that checked exceptions must be caught or declared.
- Read an exception and its stack trace
- Catch the exceptions a program can expect, recover from them in a sensible way, handle several kinds in the right order, and run cleanup code whatever happens.
- Catch an exception and recoverWrite a try-catch statement, trace how control moves through it, and recover from bad input instead of letting the program crash.
- Handle several exception types in the right orderUse several catch clauses or a multi-catch, order them from specific to general, and decide where a try block should start and end.
- Run cleanup code with finallyAdd a finally block, trace when it runs in every path through a try statement, and avoid the mistakes that make finally hide problems.
- Catch an exception and recover
- Signal problems from your own methods with throw, declare checked exceptions with throws, and create exception classes that tell callers exactly what went wrong.
- Throw exceptions and declare them with throwsValidate arguments and object state by throwing standard exceptions, declare checked exceptions in method headers, and decide where an exception should be handled.
- Create custom exception classes and keep the causeWrite your own checked or unchecked exception classes, throw them before changing an object's state, and wrap a low-level exception without losing it.
- Throw exceptions and declare them with throws
- Point a program at the right file, understand how text is stored as bytes and lines, and make sure every opened file is closed with try-with-resources.
- Work with paths, encodings and line endingsBuild paths to files, predict where Java looks for a relative path, and explain how character encodings, line endings and number formats affect text files.
- Close resources automatically with try-with-resourcesUse try-with-resources to open and close files and other resources, predict the closing order, and explain how it keeps exceptions from being lost.
- Work with paths, encodings and line endings
- Read text files line by line and turn their lines into data, write and append results to files, and combine everything into a program that copes with missing files and bad records.
- Read a text file and turn its lines into dataRead a file with Scanner, Files.readAllLines or BufferedReader, split and convert each line, and skip or report lines that do not fit the expected format.
- Write and append text filesWrite text to a new or existing file, append without erasing what is there, and make sure everything written actually reaches the file.
- Build a robust file-processing programCombine reading, parsing, exceptions and writing in one program that stops cleanly on whole-file failures, skips and reports bad records, and avoids partial output.
- Read a text file and turn its lines into data
Exceptions and Files in Java study guide
1Understand what exceptions are and how Java classifies them
A program can compile successfully and still fail when it receives an empty array, invalid text, or a missing file. The exception object and its stack trace give you evidence about that failure. Read the trace back through the active method calls, then use the class hierarchy to decide whether Java requires a handling decision at compile time. This prepares you to distinguish bugs to fix from expected problems your program can recover from.
1.1 Find the failing statement
An exception is an object describing a problem that interrupts a running program. Throwing it stops the current statement. Java skips the remaining normal work until it finds a matching handler; without one, the exception passes back through the methods that called it.
Recognize the kind of problem
A missing semicolon is a compile-time error: the program cannot compile. An exception occurs when compiled code runs with data that triggers a problem.
| Exception | Typical trigger |
|---|---|
ArithmeticException | Integer division by zero |
ArrayIndexOutOfBoundsException | a[3] when the array has length 3 |
IndexOutOfBoundsException | list.get(list.size()) |
NullPointerException | Calling a method through null |
NumberFormatException | Integer.parseInt("12a") |
InputMismatchException | Scanner.nextInt() meets "ten" |
ClassCastException | Casting an object to a class it does not belong to |
Array indexes start at 0, so length 3 means valid indexes 0, 1 and 2. Floating-point division follows different rules: 10.0 / 0 produces Infinity; it does not throw the integer-division exception.
Read a trace from the top
Here is a complete class, with no blank lines before the first line:
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));
}
}
The array is empty, so its length is 0. The division on line 5 fails. The trace is:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at Average.average(Average.java:5)
at Average.main(Average.java:9)
- Read the first line for the exception class and message.
- Read the top
atframe for the point where the problem was detected. - Read downward for callers:
maincalledaverageon line 9. - If the top frames belong to Java's library, find the first frame naming your own class. For a failed
Integer.parseInt, library frames can precede the call in your code.
The trace follows the call stack, the chain of active method calls. It tells you where to investigate, but the bad value may have been created earlier. Here the division detects the problem; the caller supplied the empty array. Decide whether an empty input should be rejected or handled before computing an average.
Inspect the exception object
e.getMessage() returns the message and can return null. e.toString() includes the class name and, when present, the message. e.printStackTrace() prints the trace to standard error. A Caused by: section shows an earlier exception retained inside a wrapper.
JVM-generated NullPointerException messages normally identify the null expression. An explicitly created exception can instead have a custom message or none. Follow the reference back to where it should have received an object.
An unhandled exception leaving main ends the main thread; that ends a single-threaded program. Fix bugs such as wrong indexes in the code. Plan recovery for expected external problems, such as a missing file or invalid user input.
Key Takeaways
- An exception interrupts normal execution; skipped statements do not resume automatically.
- Read the exception class and message, then follow stack frames from the detected failure to its callers.
- Library frames can appear before the first frame in your own code.
- The failing statement may reveal a bad value created earlier.
- Fix programming bugs and handle expected input or file failures.
1.2 Checked and unchecked exceptions
Exception classes use the inheritance rules you already know. A thrown subclass object also belongs to its superclass, which explains both Java's exception categories and how a handler matches them.
Follow the hierarchy
Only objects of Throwable or its subclasses can be thrown. Two main branches sit below it:
Throwable
Error
OutOfMemoryError
StackOverflowError
Exception
RuntimeException
IllegalArgumentException
NumberFormatException
NullPointerException
IndexOutOfBoundsException
ArrayIndexOutOfBoundsException
IOException
FileNotFoundException
NoSuchFileException
Error describes serious failures of the running environment. An ordinary application should not try to recover from an exhausted heap or a stack exhausted by endless recursion. Exception describes problems an application may handle, including its RuntimeException branch.
| Category | Classes | Compiler requirement |
|---|---|---|
| Unchecked | RuntimeException, Error, and their subclasses | Catching or declaring is optional |
| Checked | All other Throwable subclasses | Catch or declare when the code can throw them |
Both kinds are thrown at run time. The word "checked" describes the compiler checking your handling, not an earlier moment when the failure occurs. Unchecked also does not mean harmless: an unhandled null reference can stop a program.
Apply catch or declare
Reading a file can fail even in correct code. A helper can leave the decision to its caller:
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 can throw the checked IOException. The declaration passes that possibility to the caller, which must catch it or declare it too. Removing throws IOException without adding a handler makes the helper fail compilation. A method using Integer.parseInt has no comparable compiler obligation because NumberFormatException is unchecked.
Checked failures often describe conditions a caller can plan for, such as a file disappearing. Runtime failures often identify bugs or invalid arguments. These are useful design reasons, but the superclass chain determines the category. A custom class extending RuntimeException remains unchecked even when a caller could recover.
Match handlers through inheritance
catch (IOException e) can handle a FileNotFoundException or NoSuchFileException. catch (Exception e) also catches runtime exceptions; it can turn a coding bug into a misleading input message. catch (Throwable e) reaches the Error branch too and is rarely appropriate for ordinary recovery.
To classify an unfamiliar class, trace its inheritance upward in the API documentation. InputMismatchException extends NoSuchElementException, which extends RuntimeException, so it is unchecked. InterruptedException extends Exception outside the runtime branch, so it is checked. Declaring an unchecked type in a throws clause is allowed, but does not change its category.
Key Takeaways
RuntimeException,Error, and all their subclasses are unchecked.- Other
Throwablesubclasses are checked; code that can throw them must catch or declare them. - Both checked and unchecked exceptions occur at run time.
- A catch for a superclass also matches its subclasses.
- A broad
Exceptionhandler can hide programming bugs. - Classify an unfamiliar exception by its superclass chain.
2Handle exceptions with try, catch and finally
Handling a failure changes which statements run next. A useful handler must match the exception and leave the program ready to continue, while cleanup must also run on paths that leave early. Follow conversions and loops step by step, choose specific handlers before general ones, and place the protected block around the work that should fail together. Then trace how finally behaves when an exception propagates or a method returns.
2.1 Recover from a failed conversion
A try block marks work that may fail. A matching catch block gives the program a useful next action, such as asking for another value. Handling the exception does not retry the failed statement by itself.
Trace the branches
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");
The output is A, B, D: For input string: "4x", and E, each on its own line. The conversion fails, so Java skips C and enters the matching handler. When that handler finishes normally, execution continues after the whole statement. If conversion succeeds, the handler is skipped. If the block throws an ArithmeticException, this handler does not match; that exception propagates.
Retry with fresh input
Read an entire line before converting it. The loop below accepts a whole number and handles the end of keyboard input by reporting that no value was supplied:
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");
}
}
For inputs "twenty" and "20", the handler prints once, the loop reads a new line, and the method returns 20. trim() removes surrounding whitespace: Integer.parseInt(" 20") otherwise fails. The conversion accepts an optional sign and digits representing an in-range integer.
A token-based scanner needs a different repair. When nextInt() meets "ten", its InputMismatchException leaves that token unread. Catching and calling nextInt() again repeats the failure forever. Consume the bad token with next() or discard the line with nextLine() before retrying. hasNextInt() can check a token before conversion.
Keep the recovered state usable
A variable declared inside try exists only in that block. If later code needs the result, declare it outside and make every continuing path assign a valid value:
int quantity;
try {
quantity = Integer.parseInt("bad");
} catch (NumberFormatException e) {
quantity = 0;
}
System.out.println(quantity);
Zero is appropriate here only if the program defines it as a valid fallback. Leaving quantity unassigned in the handler causes a compile-time definite-assignment error.
Catch the narrow type you can handle. An empty handler silently loses the problem; a broad catch (Exception e) can label a null-reference bug as a bad number. Recovery should ask again, skip one item, choose a valid default, report failure, or pass a meaningful exception onward. For simple predictable boundaries, check first: index >= 0 && index < list.size() prevents both negative and too-large list indexes.
Key Takeaways
- A matching handler runs after the rest of the failing
tryblock is skipped. - A loop must read new input before trying again.
Scanner.nextInt()leaves a mismatched token unread.- Every path that continues must leave later variables initialized sensibly.
2.2 Choose handlers and the work they protect
A file can be missing, unreadable, or full of malformed records. Those failures need different responses. Several handlers let one try distinguish them, while the block's position decides how much work stops when something fails.
Put specific handlers first
Java tests handlers from top to bottom and runs the first matching one. It does not keep running later handlers for the same exception.
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 extends IOException, so it must come first. Reversing them makes the specific handler unreachable and prevents compilation. The conversion exception is unrelated to IOException, so those two handlers can appear in either order.
A checked handler must also be relevant to the protected work. Catching IOException around only int count = 5; is rejected because that block cannot throw it. This restriction does not apply in the same way to unchecked types or the broad Exception and Throwable types.
Share a handler when the response is shared
A multi-catch joins unrelated exception types with |:
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());
}
Here the missing second field triggers the index exception. A present but nonnumeric field would trigger the conversion exception, and both receive the same response. The multi-catch parameter is implicitly final. Alternatives cannot be a subclass and its superclass: FileNotFoundException | IOException is invalid because IOException already covers both.
Decide what one failure should skip
Consider the texts "3", "x", and "5". With a try around the whole loop, processing stops at "x" and the sum so far is 3. Put the try inside the loop to recover separately for each item:
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);
This prints Skipped: x and then 8. The loop continues because its body handled that record's failure. Nested handlers search outward from the innermost protected block; a nonmatching inner handler leaves an outer one a chance. Choose the smallest unit of work that should fail together: one record for bad data, the file operation for a read failure.
Key Takeaways
- Java runs at most one matching handler for each exception.
- Catch a subclass before its superclass.
- Multi-catch shares a response across unrelated exception types.
- Multi-catch cannot combine a superclass with its subclass.
- Put record-level recovery inside the loop to continue with later records.
2.3 Run cleanup before control leaves
Some work must happen whether an operation succeeds or fails. A finally block runs as control leaves its try statement, including when an exception propagates or a method returns.
Follow an unmatched exception
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");
Only 1 and 4 print before the ArrayIndexOutOfBoundsException propagates. Index 2 is outside the two-element array. The handler does not match, but finally still runs. The statement printing 5 is outside the cleanup block, so the propagating exception skips it.
If the protected work instead throws a matching NumberFormatException after printing 1, the handler prints 3, cleanup prints 4, and execution continues to 5. On a successful path, no handler runs, but cleanup still does.
Return values are prepared before cleanup
class Cleanup {
static int result() {
try {
return 1;
} finally {
System.out.println("cleanup");
}
}
}
The return expression is evaluated first. Java then prints cleanup, and the caller receives 1. A break or continue leaving a protected region also runs its cleanup before the control transfer takes effect.
Keep return out of finally. A return 2; there would replace the pending return value and could even discard a pending exception. An exception thrown by cleanup can likewise replace the original failure. Cleanup should not introduce a second competing result. The compiler's -Xlint:finally option warns when a finally block cannot complete normally.
Close an object only if it opened
The older manual pattern needs a variable visible to the cleanup block:
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();
}
}
}
If opening fails, sc is still null, so the guard prevents cleanup from throwing a new null-reference exception. For closeable objects, try-with-resources removes this bookkeeping and handles competing failures more safely.
finally is not a guarantee against the machine stopping. System.exit ends the JVM without running this cleanup; a crash or power loss also prevents it. An infinite loop that never leaves the block never reaches its finally either.
Key Takeaways
finallyruns on normal completion, caught and uncaught exceptions, and control transfers such asreturn.- A return expression is evaluated before cleanup runs.
- Code after a
trystatement is skipped when an exception propagates;finallyis still reached. - A return or thrown exception in
finallycan hide the original result. - Try-with-resources is the usual choice for closing file resources.
- JVM termination or a block that never ends can prevent cleanup.
3Throw exceptions and design your own
An invalid request is easiest to diagnose before it changes an object. Your methods can reject bad arguments or state with standard exceptions, and expose domain problems with custom classes. The method declaration tells callers about checked failures; inheritance limits what an override can add. When translating a low-level failure into a more useful one, retain its cause so that the caller gets both context and the original diagnostic evidence.
3.1 Signal invalid arguments and state
Your methods can reject invalid requests before changing an object. Choose an exception that identifies the problem and lets the caller respond.
Throw an object now
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;
}
}
Calling setPercentage(120) throws with the message percentage must be 0 to 100, was 120. The assignment has not run, so the field retains its previous value. This is failing fast: report the invalid request at the point where you can explain it. The same check in a constructor prevents an invalid object from being returned.
throw needs an exception object, as in throw new IllegalArgumentException("bad quantity");. A class name alone is not an object. An ordinary statement directly after an unconditional throw in the same block is unreachable.
| Problem | Standard exception |
|---|---|
| Argument has an invalid value | IllegalArgumentException |
| Object is in the wrong state for the call | IllegalStateException |
Required object reference is null | NullPointerException |
| Operation is not offered by the class | UnsupportedOperationException |
| Position is outside a collection | IndexOutOfBoundsException |
Objects.requireNonNull(name, "name must not be null"), from java.util.Objects, is a convenient null check. An already-sent order rejecting another item is a state problem; a negative item quantity is an argument problem.
Declare what can leave the method
A file-reading helper can declare its checked failure:
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 is an executable statement. throws belongs to the method declaration and tells callers what checked failures they must address. It neither catches a failure nor makes the method continue after one. Each caller must catch IOException or declare it in turn. A catch can also rethrow the same object with throw e;.
Catch where a useful response is possible. A helper usually cannot ask the user to select a different file, but main can. Printing "error" and returning an empty list would confuse a missing file with a genuinely empty file. A small experiment may let main declare throws IOException; a finished program handles expected failures with useful messages. Unchecked types may be declared for documentation even though the compiler does not require them.
Respect the inherited contract
If an interface declares read() throws IOException, an override may declare IOException, a narrower checked subclass, or no checked exception. It cannot broaden the declaration to Exception. It can declare unchecked types. An override of Object.toString() cannot add IOException, since the inherited method declares no checked exceptions. Calls through the interface type must still address its declared IOException, even when one implementation declares none.
Key Takeaways
- Use
throwwith an exception object to stop an invalid operation. - Validate before changing fields or collections.
throwsdeclares a possible failure; it does not handle it.- Catch where meaningful recovery is possible; otherwise pass the failure to the caller.
- Overrides cannot add new or broader checked exceptions.
3.2 Describe domain failures and preserve their causes
A standard exception is often enough. Create a custom class when callers need to recognize a problem specific to the program, such as insufficient stock or a malformed data record, and respond differently to it.
Choose the superclass deliberately
Extending Exception creates a checked exception. Extending RuntimeException creates an unchecked exception. Use the checked design when callers should plan for a recoverable domain failure; use the unchecked design for misuse or a programming bug.
class OutOfStockException extends Exception {
public OutOfStockException(String message) {
super(message);
}
}
super(message) stores the message in the inherited exception machinery, so getMessage() returns it. The class name conventionally ends in Exception. Extra fields and getters can expose structured details such as requested and available counts.
Leave stock unchanged after failure
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);
}
}
Starting with 12 pens, removing 5 leaves 7. A later request for 10 throws, and 7 remain because the update comes after all checks. The caller must handle or declare the checked stock failure; the invalid-quantity failure is unchecked. A program needing a distinct unknown-item response could use a related UnknownItemException, with both domain types under an InventoryException base class.
Wrap without losing the original problem
A parser can translate a low-level conversion failure into a record-level failure:
class InvalidRecordException extends Exception {
public InvalidRecordException(String message) {
super(message);
}
public InvalidRecordException(String message, Throwable cause) {
super(message, cause);
}
}
Inside the parsing method, a handler can do this:
catch (NumberFormatException e) {
throw new InvalidRecordException(
"Line 3: quantity is not a number: x", e);
}
The wrapper gives the caller a meaningful category and line number. Its getCause() returns the original NumberFormatException, and a printed trace retains a Caused by: section. Building a new exception with only the old message loses the original object and its trace.
java.io.UncheckedIOException is a ready-made unchecked wrapper specifically for IOException. Its constructors accept the cause, with an optional message. It can carry a file failure through an override that cannot add a checked declaration. Wrapping changes the type the caller sees; it does not repair the file problem. Keep ordinary loop decisions as conditions and break, without inventing exceptions for routine flow.
Key Takeaways
- Custom classes let callers recognize meaningful domain failures.
- Extend
Exceptionfor a checked class orRuntimeExceptionfor an unchecked class. - Call
super(message)to retain a useful diagnostic. - Validate the entire request before updating state.
- Pass the original exception as a cause when wrapping it.
UncheckedIOExceptioncarries anIOExceptionas an unchecked failure.
4Locate files and close resources safely
A text file must be found, decoded, and closed correctly. A relative path depends on the working directory, while bytes become readable characters only through the right encoding. Numeric text and line endings introduce their own portability choices. Once a file is open, try-with-resources releases it on every exit and keeps the main failure visible if closing also fails. These choices make later reading and writing code easier to trust.
4.1 Make text files work across computers
A file stores bytes, while your program works with characters and numbers. A successful read needs the right location, the right character encoding, and a clear convention for lines and numeric text.
Find the actual location
A relative path starts from the program's working directory. It does not start from the folder holding the source code. An absolute path starts from the file-system root, such as /home/ana/data/scores.txt, or a drive root on 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());
Import java.nio.file.Path. Creating this Path opens nothing and checks no existence. toAbsolutePath() reveals where Java will look, and getFileName() gives scores.txt. An IDE often uses the project folder as the working directory. Forward slashes in "data/scores.txt" work on Windows, Linux and macOS. A Windows path literal using backslashes needs escaping, as in "C:\\data\\scores.txt". The older java.io.File represents a location too; convert with toPath() or toFile().
Match bytes to characters
UTF-8 encodes every Unicode character. Basic Latin characters take one byte; others take two to four. The text "café" contains four characters but five UTF-8 bytes because "é" takes two. Reading those bytes as ISO-8859-1 can produce "café". Use the encoding the writer used.
The text methods of Files default to UTF-8. Classes such as FileWriter and a scanner opened without a charset use the default charset, which became UTF-8 in Java 18; older installations can differ. StandardCharsets.UTF_8, from java.nio.charset, makes the choice explicit. Invalid bytes read by Files.readAllLines produce MalformedInputException, an IOException subclass.
Read lines without leftover endings
| Convention | Java string escape |
|---|---|
| Linux and macOS line ending | \n |
| Typical Windows line ending | \r\n |
With a terminator after each line, "a" and "b" need four bytes with LF endings and six with CRLF endings. BufferedReader.readLine(), Files.readAllLines, and Scanner.nextLine() remove recognized line endings. Splitting a complete string with split("\n") leaves the Windows \r, so converting "12\r" with parseInt fails. Prefer line-reading methods, or trim the text. System.lineSeparator() and formatting %n produce the current system's ending.
Keep numeric files consistent
Integer.parseInt accepts integer text, with no decimal separator. Double.parseDouble("3.5") accepts a period; Double.parseDouble("3,5") fails. These parsing methods ignore locale. Scanner numeric methods and ordinary decimal formatting follow locale, so German or Dutch settings may expect "3,5" and produce "3,50". Use scanner.useLocale(Locale.ROOT) and String.format(Locale.ROOT, "%.2f", value) for period-decimal data; import java.util.Locale.
Missing locations commonly produce NoSuchFileException with Files or Scanner(Path), while older file-name constructors can give FileNotFoundException. Permission failures can give AccessDeniedException. These are checked I/O failures: a correct path expression alone cannot prevent them.
Key Takeaways
- Relative paths are resolved from the working directory.
- Creating a
Pathdoes not open or check the file. - Match reading and writing encodings; choose UTF-8 explicitly where defaults can vary.
- Line-reading methods remove LF, CRLF, and CR terminators.
Double.parseDoubleuses a period; locale-sensitive numeric methods need a chosen locale.- Opening and reading files still require checked-exception handling.
4.2 Let Java close every opened resource
An open file uses an operating-system resource. Closing releases it and flushes a writer's pending output. A forgotten close can exhaust open-file limits, lose buffered text, or leave another program unable to change the file.
Declare resources in the try header
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);
}
}
}
}
The header opens the reader. The body uses it, and Java closes it when the body ends normally, returns, or throws. No separate finally is needed. There is no handler here, so any checked failure still passes to the caller through throws IOException.
A resource must implement AutoCloseable. That interface declares close() and permits Exception; its Closeable subinterface narrows the declared checked failure to IOException. Readers, writers, and Scanner qualify. A String does not. Header variables are implicitly final and are available in the body, not in that statement's catch or finally blocks. Java 9 and later also allow an existing final or effectively final variable: try (in) { ... }.
Close in reverse order
Separate resources with semicolons:
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();
}
}
This is a block inside a method declaring IOException, with distinct source and target paths. Java opens in first, then out, and closes out before in. If opening out fails, the already-open reader is still closed. Opening a writer on the input path would truncate that input, so the paths must differ for this direct copy.
Resource closing happens before catch and finally clauses belonging to the same statement. Those handlers can receive failures from opening, using, or closing the resources.
Keep the main failure visible
Suppose the body throws a record exception, then closing the reader throws an IOException. Try-with-resources propagates the body exception and attaches the closing failure as suppressed. getSuppressed() retrieves it, and the trace prints a Suppressed: section. The original body failure stays visible. If the body succeeds and closing alone fails, the closing exception propagates normally.
With multiple failures during closing, Java still attempts the remaining closes. A plain finally { resource.close(); } can instead replace a pending body failure with a cleanup failure.
Use this pattern for file resources your code owns. Closing a scanner on System.in also closes the program's keyboard input, preventing later reads. Keep ownership of shared standard input at the program level instead of closing it in a helper.
Key Takeaways
- Try-with-resources closes successfully opened resources on normal and exceptional exits.
- Only
AutoCloseableobjects qualify as resources. - Resources open left to right and close right to left.
- Closing precedes the same statement's catch and finally blocks.
- A body failure stays primary; later closing failures are suppressed.
- Automatic closing does not replace catch-or-declare handling.
- Closing a scanner also closes its closeable input source.
5Read and write text files
File processing connects external bytes to the objects and results your program uses. Read lines with a method suited to the input size, validate fields before conversion, and write with a deliberate replacement or append policy. A complete report needs separate responses for a bad record and an unusable file. Build the result before saving it, then use temporary output and a supported atomic move when an existing destination must be protected.
5.1 Read lines and turn them into objects
Reading gives you text. Parsing gives that text a meaning: a count, an age, or an object. Keep those two operations separate so a bad record does not look like a failed file read.
Choose how much to hold in memory
| Method | Result and use |
|---|---|
Files.readAllLines(path) | A list containing every line; convenient for small files |
Files.readString(path) | One string retaining line endings |
BufferedReader.readLine() | One line at a time; null signals the end |
Scanner.hasNextLine() / nextLine() | Convenient line-by-line reading |
Import java.nio.file.Files and Path, plus the reader or collection types you use. Files text methods default to UTF-8. A BufferedReader belongs in try-with-resources and reports reading failures with IOException. Reading one line at a time avoids holding the entire input in memory, unless your processing stores all the records afterward.
A scanner also needs closing, and one extra failure check:
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();
}
}
}
Opening can throw directly. During reading, Scanner treats an underlying I/O failure as end of input and stores it; ioException() exposes it. Without that final check, a partial read can look successful.
Count physical lines, then parse
For input lines "12", "15", "abc", an empty line, and "9", increment the line number before deciding whether to skip a blank. Convert each nonblank line with Integer.parseInt(line.trim()) inside its own try. Report "Line 3: not a number: abc" and continue. The valid sum is 36 and count is 3, giving average 12.0. Compute (double) sum / count to preserve a fractional result, and check that the count is not zero first.
Check fields before indexing
Simple comma-separated data can become objects. Here the first line is a required header; each remaining record has a nonempty name and integer age:
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");
}
This loop-body fragment assumes line, lineNumber, a List<Person> named people, and a Person(String, int) constructor. Skip the header "name,age" before this parsing step; otherwise "age" fails numeric conversion. The records "Ana,34", "Ben,29", and "Chen,41" total 104 years and average about 34.67.
Plain split(",") drops trailing empty fields: "Eve," produces only one part. The -1 limit keeps the empty second field so validation can report it. Always check length before parts[1]. Splitting alone does not handle quoted commas, such as the name in ""Smith, Ana",34"; full CSV needs a CSV parser.
Key Takeaways
- Choose whole-file methods for manageable inputs or a reader loop for large ones.
- Check
Scanner.ioException()after reading to detect a hidden read failure. - Count original file lines even when blanks or records are skipped.
- Check field count and required values before indexing and converting.
- Skip a header before parsing records.
- Plain splitting cannot parse quoted CSV fields.
5.2 Write complete text and append deliberately
Opening an output file can change it immediately. Choose replacement or appending before opening the writer, and finish by closing it so buffered output is not left in memory.
Replace or append
Files.writeString(path, text) writes one string. Files.write(path, lines) writes an iterable of lines, adding the system line separator after each, including the last. With their default options, both create a missing file and truncate an existing one.
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 allows a new file; APPEND preserves old content and adds at the end. APPEND alone fails if the file is absent. Appending does not insert a missing separator before your text: if an existing file ends halfway through a line, the next characters continue that line.
The older FileWriter has an append flag: new FileWriter("log.txt", StandardCharsets.UTF_8, true). Without append, a new FileWriter or a file-name PrintWriter truncates an existing file too. Never open a replacing writer on input you still need to read.
Choose a writer and notice failures
BufferedWriter supports write and newLine(), and reports write failures as checked exceptions:
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();
}
}
}
The file has two lines: "Readings: 3" and "Average: 3.00". Locale.ROOT fixes the decimal point. newLine(), println, and %n all use the platform line ending; a literal \n writes LF on every system.
A PrintWriter offers convenient print, println, and printf, but those methods record I/O failures instead of throwing them. checkError() flushes and reports its error flag. When checking final close failures too, retain access to the writer and check after closing. For code that must reliably propagate writing failures, use BufferedWriter or the Files methods.
Complete the round trip
Writers buffer output. flush() sends pending text onward; close() flushes and releases the file. Try-with-resources ensures closing is attempted on every exit, but cannot make a disk write succeed.
To save a person, write the name, a comma, and the integer age, then a line ending. Format decimals with Locale.ROOT, so a later Double.parseDouble can read them. A missing parent directory is not created by opening a file: use Files.createDirectories(folder) when creating it is intended, or report the failure. A write can fail after truncation or partial output; use temporary output and an atomic move when the destination must be protected.
Key Takeaways
- Default writing creates a missing file and truncates an existing one.
- Use
CREATEwithAPPENDto retain old content and allow a new log. - Closing flushes buffered output and releases the resource.
PrintWriterrecords write errors;checkError()exposes them.BufferedWriterandFilesmethods propagate I/O failures.- Use UTF-8 and
Locale.ROOTfor a portable text round trip. - Writing a file does not create missing parent folders.
5.3 Build a report without hiding failures
A robust file processor needs two recovery levels. A bad record can be skipped and reported; a failure to read or save the file stops the task. Compute a complete result before touching its destination.
Read, validate, compute, save
The complete program below reads optional header "date,temperature" followed by simple two-field records. Dates are nonempty labels; temperatures are finite numbers in degrees Celsius. It skips and reports malformed records, including blank lines. The nested checked exception keeps record problems separate from file problems.
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());
}
}
}
Follow one run
Use these five input lines without a header:
2026-03-01,4.5
2026-03-02,6.0
2026-03-03,abc
2026-03-04,-1.5
missing comma
Lines 1, 2, and 4 produce three valid readings. The sum is 9.0; average is 3.00 °C, minimum is -1.50 °C, and maximum is 6.00 °C. Lines 3 and 5 produce diagnostics, and the report records two skipped lines. The parsing handler sits inside the loop, so each bad record leaves later records reachable. Updating totals only after successful parsing keeps rejected values out.
Double.parseDouble accepts special strings such as "NaN" and "Infinity". Double.isFinite rejects them here because they cannot serve as ordinary measured temperatures. An empty file, a header-only file, or all-invalid records reaches the count-zero branch before division or use of the initial minimum and maximum.
Protect the destination
The read and computation finish before saving begins. Files.writeString opens and closes its own file, but can fail after writing part of it. The program therefore writes to a temporary file in the destination folder, closes it, and requests ATOMIC_MOVE. The move makes the finished result visible as one file-system operation when supported.
Replacing an existing target atomically is implementation dependent. The program reports an unsupported move or replacement and never retries with a non-atomic move. A cleanup failure is attached to the original exception instead of replacing it. Atomic visibility does not promise survival of a power loss.
Checking Files.exists(input) beforehand cannot guarantee the later read: a file can disappear or become inaccessible after the check. Handle the actual operation. Before relying on a processor, try missing input, missing output folders, empty and header-only files, CRLF endings, accented text, and malformed records. User messages should name the failed path; debugging a wrapper also needs its original cause and stack trace.
Key Takeaways
- Handle record failures inside the loop and whole-file failures outside it.
- Validate a complete record before updating counts or totals.
- Check for zero valid records before computing an average.
- Finish reading and computation before opening output.
- Write and close a temporary file, then request an atomic move to protect the destination.
- Report unsupported atomic replacement instead of silently falling back.
- Keep original causes and cleanup failures available for diagnosis.
Exceptions and Files in Java examples
1Follow a failure back to its cause
11 steps
- 1IntroductionA program can compile and still fail
An input value can make valid Java code fail while it runs. The exception object tells you what kind of problem occurred, and the stack trace shows which method calls were active.
Follow a failed integer conversion first. Then use the same inheritance rules that make subclass objects usable as superclass objects to decide what the compiler requires you to handle.
- 2ExampleWatch the conversion stop
A method
loadCountexecutes these statements:System.out.print("start "); int count = Integer.parseInt("eight"); System.out.print("finish");It prints
start, then throwsNumberFormatException. The assignment does not complete, andfinishis skipped. A matching handler can take over, but the failed statement does not resume after recovery. - 3ExplanationFollow the active calls
Suppose
maincalledloadCount, which calledInteger.parseInt. Those calls form part of the call stack. The exception moves outward when a method has no matching handler.parseIntfails first,loadCountcannot finish its normal work, and the caller gets a chance to handle the failure. If it leavesmainunhandled, Java reports the exception and the main thread ends. - 4ExampleFind your first frame
A trace can include these application frames after Java's library frames:
at Counts.loadCount(Counts.java:14) at Counts.main(Counts.java:5)Inspect line 14 first: that is the call in your code nearest to the detection point. Line 5 tells you where
loadCountwas called. The exception's first line gives its class and message; do not confuse the lower caller frame with the statement that first used the bad text. - 5ChallengeFind the skipped output
A helper prints
A, callsInteger.parseInt("q2"), then would printB. Its caller catchesNumberFormatExceptionand printsC. What letters print, and why?---reveal---
AthenC. The conversion throws beforeB; propagation takes the failure to the caller's matching handler. The helper's remaining statements are abandoned, so recovery does not return to printB. - 6TipLook beyond the detected statement
The statement where a failure is detected may be using a bad value created earlier. A null-reference failure tells you to trace where that reference should have received an object.
Use
getMessage()for diagnostic text andprintStackTrace()for the call chain. A message can benull; aCaused by:section supplies another exception retained inside a wrapper. - 7ExplanationUse the superclass chain
Throwableis the base class for throwable objects. Its main branches areErrorandException;RuntimeExceptionsits underException.RuntimeException,Error, and every subclass of either are unchecked. OtherThrowablesubclasses are checked. Both categories fail during execution; "checked" describes the compiler's check of handling, not a different time when the exception is thrown. - 8ExampleCompare a parser and a file reader
NumberFormatExceptionextendsIllegalArgumentException, thenRuntimeException, so a call toInteger.parseInthas no compulsory handler.IOExceptionextendsExceptionoutside that branch. A call toFiles.readStringmust catch its possibleIOExceptionor declare it withthrows. A file can fail for external reasons even when the calling code is correct. - 9ChallengeClassify an unfamiliar failure
BadRecordExceptionextendsExceptiondirectly. A helper declares that it may throw this type. What must its caller do, and when is that obligation checked?---reveal---
Catch it or declare an applicable checked type in the caller's method declaration. The compiler enforces that obligation because the class is outside the unchecked branches. Whether one particular run succeeds does not remove the declaration-level requirement.
- 10ChallengeExplain a surprisingly broad handler
A file-reading block catches
Exceptionand prints "File problem". It instead fails with aNullPointerExceptioncaused by a bug. Will the handler receive it, and is that message reliable?---reveal---
Yes:
NullPointerExceptionextendsRuntimeException, which extendsException. The message is misleading because this failure is a code bug, not evidence of a file problem. Read the trace and narrow the expected handler to the failures it can explain. - 11RecapChoose the next debugging action
Start a failure investigation with its class, message, and first application frame. Follow callers and the origin of bad values when the detected statement alone does not explain the cause.
Then check inheritance before choosing handling: checked failures require a compiler-visible decision; unchecked bugs still need correction. Keep broad handlers from disguising one kind of problem as another.
2Trace recovery and cleanup paths
12 steps
Save this lesson to follow every Walkthrough step by step.
- 1IntroductionDecide what should happen next
- 2ExampleRecover after the whole statement
- 3TipMake a retry read new text
- 4ChallengeRepair the stuck scanner
- 5ExplanationGive a specific failure its own response
- 6ExampleLet the loop continue
- 7ChallengeMove the protected boundary
- 8Key InsightShare responses without overlapping types
- 9ExplanationCleanup runs before leaving
- 10ChallengeTrace an unmatched failure
- 11ChallengeKeep cleanup from hiding a retry failure
- 12RecapTrace the next reachable statement
3Reject a request without damaging state
11 steps
Save this lesson to follow every Walkthrough step by step.
- 1IntroductionPreserve a usable object
- 2ExampleValidate before subtraction
- 3ExplanationSeparate throw from the declaration
- 4ChallengeChoose the right standard failure
- 5ConnectionAn override keeps promises to callers
- 6ExampleGive insufficient stock its own type
- 7ExampleKeep the failed request separate
- 8ChallengeDecide what state survives
- 9ExplanationRetain the original conversion failure
- 10ChallengePass a file failure through a restricted method
- 11RecapDesign an exception the caller can use
4Open the right text and close it safely
12 steps
Save this lesson to follow every Walkthrough step by step.
- 1IntroductionLocation and lifetime both matter
- 2ExampleResolve from the working directory
- 3ExplanationDecode with the writer's charset
- 4TipRemove a complete line ending
- 5ChallengeMake a decimal survive the round trip
- 6ExplanationDeclare a resource to close
- 7ConnectionUse the closing contract
- 8ExampleReverse the opening order
- 9ChallengeTrace a failed second opening
- 10Key InsightKeep a body failure as the main report
- 11ChallengeSeparate data failure from cleanup failure
- 12RecapInspect a file operation in order
5Turn readings into a dependable report
16 steps
Save this lesson to follow every Walkthrough step by step.
- 1IntroductionA report needs more than correct arithmetic
- 2ExplanationChoose how lines arrive
- 3ExampleDefine the record before parsing
- 4ExampleValidate before using the second field
- 5ChallengeLocate the rejected record
- 6ExplanationChoose replacement or appending
- 7ExampleWrite a portable report line
- 8TipNotice a write that failed
- 9ChallengeKeep both old and new log entries
- 10ConnectionRecover at two different levels
- 11ExampleUpdate totals only after validation
- 12ChallengeHandle a value that parses but cannot serve
- 13ExplanationFinish output before replacing the target
- 14TipKeep the save failure visible
- 15ChallengeChoose what can safely be reported
- 16RecapReview the processor by failure path
Exceptions and Files in Java practice questions
Set 1: Trace failures and choose useful recovery10 Practice Questions
Question 1 of 10
values[5]?Show answerHide answer
ArrayIndexOutOfBoundsException at that access. Counting five elements does not make index 5 valid: the fifth element is at index 4.Question 2 of 10
DataProblem extends Exception directly. What obligation does a method have when it calls a helper declared throws DataProblem?Show answerHide answer
DataProblem is checked because it extends Exception outside the RuntimeException branch. The calling code must catch it or declare an applicable checked type. The compiler checks the declared possibility, even if a particular call would succeed.Question 3 of 10
What letters print, in order?
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");
Show answerHide answer
NumberFormatException before the statement printing Q. The matching handler prints R, then execution continues after the statement and prints S. The skipped statement does not run after recovery, so PQRS cannot be the output.Question 4 of 10
NoSuchFileException or another IOException. What catch order gives each its own response?Show answerHide answer
NoSuchFileException extends IOException, so its specific handler must appear first. Putting IOException first would already catch every missing-file exception and make the later handler unreachable. A multi-catch cannot combine these related types either.Question 5 of 10
What does calling pick() print and return?
static int pick() {
try {
return 8;
} finally {
System.out.print("done");
}
}
Show answerHide answer
finally before delivering that value to its caller. It therefore prints done and returns 8. A return inside try does not bypass cleanup; only a competing transfer from cleanup would replace that result.Question 6 of 10
Show answerHide answer
IllegalArgumentException describes the failure. IllegalStateException would describe a call forbidden by the object's current state. No parsing operation is stated, so a numeric argument alone does not make this a number-format failure.Question 7 of 10
/work/app. It creates Path.of("data", "levels.txt"). What absolute location does that relative path identify?Show answerHide answer
/work/app to /work/app/data/levels.txt. Java does not insert a source folder. Placing the file beside source code would work only if that happened to be the location the resolved path names.Question 8 of 10
a opens, but opening resource b throws. Both are declared in the same try-with-resources header, in that order. Closing a also throws. Which failure reaches the caller?Show answerHide answer
b fails, Java still closes the already-open a. The opening failure stays primary and the later closing failure is attached as suppressed. Choosing the closing failure as primary confuses try-with-resources with manual cleanup that can overwrite an earlier failure.Question 9 of 10
BufferedReader has reached the end of its file. What does the next readLine() return?Show answerHide answer
BufferedReader.readLine() returns null when no characters remain to form another line. An empty string represents a real blank line, so using it as the end marker would stop too soon. Line terminators are removed from returned lines and are not an end-of-file marker.Question 10 of 10
Files.writeString preserve any existing text and add new text at the end?Show answerHide answer
APPEND writes after existing content, and CREATE permits a missing file to be created. Using only APPEND fails when the log does not exist. TRUNCATE_EXISTING would erase existing content, while CREATE_NEW rejects a path that already exists.Set 2: Apply contracts to records and file output10 Practice Questions
Save this lesson to see every answer and practice every set.
Question 1 of 10
A trace begins with these frames. Which line in the learner's class should be inspected first?
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)
Show answerHide answer
Save this lesson to see this answer.
Question 2 of 10
AmountProblem extends IllegalArgumentException. How is it classified?Show answerHide answer
Save this lesson to see this answer.
Question 3 of 10
InputMismatchException from Scanner.nextInt(), prints a message, and immediately calls nextInt() again. The next token is "many". Why does the loop keep failing?Show answerHide answer
Save this lesson to see this answer.
Question 4 of 10
void load() throws IOException. An implementation needs to declare a missing-file failure. Which checked declaration is allowed on its override?Show answerHide answer
Save this lesson to see this answer.
Question 5 of 10
remove method rejects requests larger than the current stock before changing the map. Calls remove 6, then request 14; the second failure is wrapped with its cause and caught by the caller. What stock and diagnostic information remain?Show answerHide answer
Save this lesson to see this answer.
Question 6 of 10
Double.parseDouble("6,25") runs on a computer using German locale settings?Show answerHide answer
Save this lesson to see this answer.
Question 7 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 8 of 10
line.split(",") and line.split(",", -1)?Show answerHide answer
Save this lesson to see this answer.
Question 9 of 10
PrintWriter, but a full disk prevents the text from being saved. What should it use to detect the writer's recorded error?Show answerHide answer
Save this lesson to see this answer.
Question 10 of 10
Show answerHide answer
Save this lesson to see this answer.
Set 3: Trace interacting failures and cleanup10 Practice Questions
Save this lesson to see every answer and practice every set.
Question 1 of 10
NumberFormatException when caught by a superclass handler?Show answerHide answer
Save this lesson to see this answer.
Question 2 of 10
What value is printed?
int count;
try {
count = Integer.parseInt("bad");
} catch (NumberFormatException e) {
count = 4;
}
System.out.println(count + 2);
Show answerHide answer
Save this lesson to see this answer.
Question 3 of 10
What value reaches the final print?
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);
Show answerHide answer
Save this lesson to see this answer.
Question 4 of 10
What does result() do?
static int result() {
try {
throw new IllegalArgumentException("bad");
} finally {
return 9;
}
}
Show answerHide answer
Save this lesson to see this answer.
Question 5 of 10
NumberFormatException e. Its custom InvalidRecordException has message-only and message-plus-cause constructors. How should it add "Line 8" while retaining the original trace?Show answerHide answer
Save this lesson to see this answer.
Question 6 of 10
Files.readString(path).split("\n"), then Integer.parseInt on each nonempty piece. Why can a piece containing the digits "27" fail conversion?Show answerHide answer
Save this lesson to see this answer.
Question 7 of 10
a and b open successfully in that order. The body throws E; closing b throws F; closing a throws G. What reaches the catch attached to that try-with-resources statement?Show answerHide answer
Save this lesson to see this answer.
Question 8 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 9 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 10 of 10
Files.exists, then read with a scanner. Its loop ends after only some records because the underlying reader failed, and the program immediately starts saving. What must change to prevent this partial input from being treated as success?Show answerHide answer
Save this lesson to see this answer.
Set 4: Diagnose and improve a complete processor10 Practice Questions
Save this lesson to see every answer and practice every set.
Question 1 of 10
What prints before the exception leaves main, and which application frame is first in its trace?
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");
}
}
Show answerHide answer
Save this lesson to see this answer.
Question 2 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 3 of 10
catch (NumberFormatException | IllegalArgumentException e). Why does this multi-catch fail to compile?Show answerHide answer
Save this lesson to see this answer.
Question 4 of 10
What does choose() print and return?
static int choose() {
int value = 5;
try {
return value;
} finally {
value = 12;
System.out.print(value);
}
}
Show answerHide answer
Save this lesson to see this answer.
Question 5 of 10
ReaderTask declares String read() throws IOException. Class FixedTask implements it with public String read() and no checked declaration. Variable task has type ReaderTask and refers to a FixedTask. What must code calling task.read() do?Show answerHide answer
Save this lesson to see this answer.
Question 6 of 10
IOException. Which standard wrapper retains that cause while exposing an unchecked failure?Show answerHide answer
Save this lesson to see this answer.
Question 7 of 10
close() then throws IOException, and the attached catch returns 2; its finally block prints "closed" without throwing. What does the method do?Show answerHide answer
Save this lesson to see this answer.
Question 8 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 9 of 10
Double.parseDouble for its second field on computers using any locale. Which writing approach meets that format?Show answerHide answer
Save this lesson to see this answer.
Question 10 of 10
Show answerHide answer
Save this lesson to see this answer.
Stuck on your own question? Homework Help
Key Terms
A
Absolute path
toAbsolutePath() shows the absolute path used to diagnose a file placed in the wrong folder.Appending
ArithmeticException
ArithmeticException at the division.Atomic move
AutoCloseable
AutoCloseable can print its name when automatic cleanup calls close().B
Buffer
BufferedReader
BufferedReader loop processes a large input until readLine() returns null at the end.BufferedWriter
BufferedWriter writes a report line and then uses newLine() to add the platform line ending.C
Call stack
main calls load, which calls parse, the call stack records all three active method calls.catch clause
NumberFormatException can ask for another number after the user types "many".Catch order
NoSuchFileException before IOException when each needs a separate message.Catch-or-declare rule
Files.readString, even when the file it reads exists.Cause
InvalidRecordException can be the NumberFormatException raised by its numeric field.Character encoding
Checked exception
IOException is a checked exception, so a file-reading helper must catch it or declare it.Cleanup
Closeable
BufferedReader implements Closeable, so it qualifies for a try-with-resources declaration.CSV
Custom exception
E
Error
OutOfMemoryError belongs to Error; catching ordinary invalid input does not address an exhausted heap.Exception
Exception chaining
Exception hierarchy
Exception masking
finally can cause exception masking by discarding a failure raised in the try block.F
Failing fast
Field
finally block
return reaches the caller.Flushing
H
Header row
I
IllegalArgumentException
IllegalArgumentException when its required positive quantity is supplied as -2.IllegalStateException
IllegalStateException when code tries to add another item to it.InputMismatchException
nextInt() throws InputMismatchException on "several" and leaves that token available to be discarded.L
Line ending
BufferedReader.readLine() is removed before the method returns the line text.Locale
M
Multi-catch
N
NullPointerException
name.trim() when name is null throws NullPointerException before any trimmed text is returned.NumberFormatException
Integer.parseInt("blue") throws NumberFormatException because the text cannot represent an integer.P
Parsing
Path
Path.of("data", "counts.txt") constructs a Path without testing whether the data folder exists.Pending return
finally does not reevaluate the expression of a pending return.PrintWriter
PrintWriter can format an average with printf, but successful return from that call does not prove saving succeeded.Propagation
Protected region
R
Record-level failure
Recovery
Relative path
data/counts.txt can identify a different file when the program starts in another folder.Resource
RuntimeException
NumberFormatException reaches RuntimeException through its superclass IllegalArgumentException.S
Scanner
Scanner needs an ioException() check after its loop so a failed read cannot look successful.Stack trace
Suppressed exception
T
Temporary file
throw
throw before field assignment rejects an invalid capacity while preserving the old field value.Throwable
Throwable through Exception, so Java can throw and catch it.throws clause
throws IOException lets a file helper report failure to a caller that can recover.Truncation
Files.writeString causes truncation, so a later write failure can leave an incomplete result.try block
Try-with-resources
U
Unchecked exception
UncheckedIOException
IOException can pass a file failure onward using UncheckedIOException.Unreachable handler
IOException first creates an unreachable handler if NoSuchFileException is caught afterward.UTF-8
W
Whole-file failure
Working directory
/work/app as the working directory, data/counts.txt points inside /work/app/data.About this lesson
Make your own Study Materials
Turn your notes, slides and documents into Study Guides, Practice Questions, Flashcards and 6 more tools.