Home
← All UnitsCS III — Unit 1: Files & Exceptions
Unit 1

Files & Exceptions

Real programs read and write files and handle errors gracefully. This unit covers the File class, reading/writing text files with Scanner and PrintWriter, and Java's exception handling system.

The File Class

A File object represents a path to a file or directory on disk. Creating a File object doesnot create an actual file — it's just a reference to a location that may or may not exist.

Java — Creating File objects
import java.io.File;

// A File object is just a path — the file may not exist yet
File f = new File("data.txt");
File dir = new File("output/reports");
File abs = new File("C:/Users/student/Desktop/scores.txt");

// The file is NOT created on disk by this.
// It's just a Java object that knows the path.
System.out.println(f.getName());  // data.txt

File Methods

MethodReturnsDescription
getName()StringThe file name (not the full path)
exists()booleantrue if the file/directory exists on disk
length()longFile size in bytes (0 if doesn't exist)
getAbsolutePath()StringThe full path from the root of the filesystem
canRead()booleantrue if the program can read this file
canWrite()booleantrue if the program can write to this file
createNewFile()booleanCreates the file if it doesn't exist. Returns true if created. Throws IOException.
delete()booleanDeletes the file. Returns true if successful.
Java — File methods in action
import java.io.File;
import java.io.IOException;

File f = new File("data.txt");

System.out.println(f.getName());           // data.txt
System.out.println(f.exists());            // false (doesn't exist yet)
System.out.println(f.getAbsolutePath());   // C:\projects\data.txt

f.createNewFile();  // actually creates the file on disk now
                     // throws IOException — must handle it!

System.out.println(f.exists());            // true
System.out.println(f.length());            // 0 (empty file)
System.out.println(f.canRead());           // true
System.out.println(f.canWrite());          // true

f.delete();                                // removes the file
System.out.println(f.exists());            // false

Tracing tip

new File("x.txt") does NOT create a file. createNewFile() does. exists() returnsfalse until the file is actually on disk. Watch for this distinction in trace questions.

Writing Files with PrintWriter

PrintWriter writes text to a file sequentially. It has the same print/println methods you already know from System.out.

Java — Writing to a file
import java.io.PrintWriter;
import java.io.File;
import java.io.IOException;

public class WriteDemo {
    public static void main(String[] args) throws IOException {
        // Creates the file if it doesn't exist; overwrites if it does
        PrintWriter out = new PrintWriter(new File("output.txt"));

        out.println("Name: Alice");
        out.println("Score: 95");
        out.print("Grade: ");
        out.println("A");

        // IMPORTANT: must close or flush to save!
        out.close();

        // output.txt now contains:
        // Name: Alice
        // Score: 95
        // Grade: A
    }
}

Critical: always close the writer

If you don't call out.close(), the data may never actually be written to disk. PrintWriter buffers output — close() flushes the buffer and releases the file.

Reading Files with Scanner

You already know Scanner for keyboard input (System.in). It works the same way with files — just pass a File object instead.

Java — Reading from a file
import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;

public class ReadDemo {
    public static void main(String[] args) throws FileNotFoundException {
        Scanner in = new Scanner(new File("data.txt"));

        // Same methods as reading from keyboard
        String line = in.nextLine();       // reads entire line
        String word = in.next();           // reads one token
        int num = in.nextInt();            // reads an integer
        double dec = in.nextDouble();      // reads a double

        in.close();
    }
}

Scanner methods for files

ReadingChecking (has more?)
next()hasNext()
nextLine()hasNextLine()
nextInt()hasNextInt()
nextDouble()hasNextDouble()

The hasNext...() methods return true if there's more data of that type to read — essential for loops.

Loops with Scanner & Files

The most common file-reading pattern: loop until there's no more data.

Java — Read all lines from a file
Scanner in = new Scanner(new File("names.txt"));

while (in.hasNextLine()) {
    String line = in.nextLine();
    System.out.println(line);
}
in.close();
Java — Read all integers and compute sum
Scanner in = new Scanner(new File("numbers.txt"));

int sum = 0;
int count = 0;

while (in.hasNextInt()) {
    sum += in.nextInt();
    count++;
}

System.out.println("Sum: " + sum);
System.out.println("Count: " + count);
System.out.println("Average: " + (double) sum / count);
in.close();
Java — Read words, skip non-integers
// File contents: "Alice 95 Bob 87 Charlie 92"
Scanner in = new Scanner(new File("mixed.txt"));

while (in.hasNext()) {
    if (in.hasNextInt()) {
        int score = in.nextInt();
        System.out.println("Score: " + score);
    } else {
        String name = in.next();
        System.out.println("Name: " + name);
    }
}
in.close();
// Output:
// Name: Alice
// Score: 95
// Name: Bob
// Score: 87
// Name: Charlie
// Score: 92

Tracing tip

hasNext() checks for any token.hasNextLine() checks for another line.hasNextInt() checks if the next token is an integer. When the file is exhausted, all return false.

What Are Exceptions?

An exception is an event that disrupts the normal flow of a program. When an error occurs, Java creates an exception object and throws it. If nobody catches it, the program crashes with a stack trace.

Java — An unhandled exception
int[] arr = {1, 2, 3};
System.out.println(arr[5]);  // throws ArrayIndexOutOfBoundsException

// If unhandled, the program crashes and prints:
// Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 5
//     at Main.main(Main.java:3)

Exception Hierarchy

All exceptions are objects that extend Throwable. The two main branches are Error (serious, unrecoverable) and Exception (can be handled).

Exception inheritance tree
Throwable
├── Error                          (serious — don't catch these)
│   ├── StackOverflowError
│   └── OutOfMemoryError
│
└── Exception                      (can be caught and handled)
    ├── IOException                (checked)
    │   └── FileNotFoundException  (checked)
    ├── ClassNotFoundException     (checked)
    │
    └── RuntimeException           (unchecked)
        ├── NullPointerException
        ├── ArrayIndexOutOfBoundsException
        ├── ArithmeticException
        ├── ClassCastException
        ├── IllegalArgumentException
        └── NumberFormatException

Checked vs Unchecked Exceptions

CheckedUnchecked
ExtendsException (not RuntimeException)RuntimeException
Compiler enforces?Yes — must handle or declareNo — compiler doesn't check
When?External problems (file not found, network error)Programmer bugs (null, bad index)
Handle withtry/catch or throwsFix the bug in your code
ExamplesIOException, FileNotFoundExceptionNullPointerException, ArithmeticException
Java — Checked exception: won't compile without handling
import java.io.File;
import java.util.Scanner;

// This WON'T compile:
// Scanner in = new Scanner(new File("data.txt"));
// Error: unreported exception FileNotFoundException; must be caught or declared

// Fix 1: declare it with throws
public static void main(String[] args) throws FileNotFoundException {
    Scanner in = new Scanner(new File("data.txt"));
}

// Fix 2: catch it with try/catch
public static void main(String[] args) {
    try {
        Scanner in = new Scanner(new File("data.txt"));
    } catch (FileNotFoundException e) {
        System.out.println("File not found!");
    }
}

try, catch, finally

try wraps code that might throw. catchhandles the exception. finally runs no matter what — whether an exception occurred or not.

Java — Full try/catch/finally
import java.util.Scanner;
import java.io.File;
import java.io.FileNotFoundException;

Scanner in = null;
try {
    in = new Scanner(new File("data.txt"));
    int num = in.nextInt();
    System.out.println("Read: " + num);

} catch (FileNotFoundException e) {
    System.out.println("File not found: " + e.getMessage());

} catch (Exception e) {
    System.out.println("Something else went wrong: " + e);

} finally {
    // ALWAYS runs — even if an exception was thrown
    if (in != null) {
        in.close();
    }
    System.out.println("Cleanup done.");
}

Execution flow

ScenarioWhat runs
No exceptiontry block → finally block
Exception is caughttry (up to error) → matching catch → finally
Exception not caughttry (up to error) → finally → program crashes
Java — Multiple catch blocks
try {
    int[] arr = {1, 2, 3};
    System.out.println(arr[5]);
} catch (ArrayIndexOutOfBoundsException e) {
    System.out.println("Bad index!");
} catch (Exception e) {
    System.out.println("Some other error");
}
// Output: Bad index!

// Catch blocks are checked TOP to BOTTOM.
// Put more specific exceptions FIRST.
// Putting Exception first would catch everything — the specific
// catches below it would never run (compiler error).

throw and throws

throw creates and throws an exception.throws declares that a method might throw an exception (passes the responsibility to the caller).

KeywordWherePurpose
throwInside a method bodyActually throws an exception object
throwsIn the method signatureDeclares what exceptions the method might throw
Java — throw vs throws
// throws — in the method SIGNATURE (declares possibility)
public static double divide(int a, int b) throws ArithmeticException {
    if (b == 0) {
        // throw — in the method BODY (actually throws)
        throw new ArithmeticException("Cannot divide by zero");
    }
    return (double) a / b;
}

// Caller must handle it:
try {
    double result = divide(10, 0);
} catch (ArithmeticException e) {
    System.out.println(e.getMessage());  // Cannot divide by zero
}
Java — Throwing custom checked exceptions
import java.io.IOException;

// throws passes the buck to the caller
public static void readConfig(String path) throws IOException {
    File f = new File(path);
    if (!f.exists()) {
        throw new IOException("Config file missing: " + path);
    }
    // ... read the file
}

// Whoever calls readConfig must either:
// 1. Wrap it in try/catch, OR
// 2. Add "throws IOException" to their own method signature

Tracing Exception Code

On exams, you'll trace through code with try/catch and predict the output. The key rule: when an exception is thrown, the rest of the try block is skipped and execution jumps to the matching catch.

Java — What does this print?
try {
    System.out.println("A");
    int x = 10 / 0;              // ArithmeticException thrown here
    System.out.println("B");     // SKIPPED
} catch (ArithmeticException e) {
    System.out.println("C");
} catch (Exception e) {
    System.out.println("D");     // not reached — caught above
} finally {
    System.out.println("E");
}
System.out.println("F");
Answer
A
C
E
F
Java — Harder trace: exception in a method
public static int process(int x) {
    System.out.println("P1");
    int result = 100 / x;
    System.out.println("P2");
    return result;
}

public static void main(String[] args) {
    try {
        System.out.println("M1");
        int val = process(0);        // throws ArithmeticException inside process
        System.out.println("M2");    // SKIPPED
    } catch (ArithmeticException e) {
        System.out.println("M3");
    } finally {
        System.out.println("M4");
    }
    System.out.println("M5");
}
Answer
M1
P1
M3
M4
M5

Tracing rules

  1. When an exception is thrown, skip the rest of the try block
  2. Check catch blocks top-to-bottom for a matching type
  3. If caught: run that catch block, then finally, then continue after the try/catch
  4. If not caught: run finally, then the exception propagates up to the caller
  5. finally ALWAYS runs (even if there's a return in try or catch)