› Module 12: File Handling & Advanced Topics › 12.2 Interfaces and Packages
M O D U L E

Module 12: File Handling & Advanced Topics

File streams with try-with-resources, packages, generic types, and modern functional Java 8+ Lambdas & Streams.

12.1 File Handling

The java.io.File class represents file metadata and disk paths (checking existence, creating directories, querying sizes), but does not read or write file contents directly. Stream classes handle actual I/O operations.

Efficient Buffered Stream Wrapping

Raw character streams (FileReader and FileWriter) read one character at a time, resulting in thousands of expensive operating system disk accesses. Wrapping them inside a BufferedReader / BufferedWriter creates an internal memory buffer, reading large blocks in a single disk hit:

try (BufferedReader br = new BufferedReader(new FileReader("data.txt"))) {
    String line;
    while ((line = br.readLine()) != null) {
        System.out.println(line);
    }
} // br is automatically closed here even if an exception occurs!
FileReader / Scanner reads a file BufferedReader (wraps for efficiency) Your program (processes data) BufferedWriter (wraps for efficiency) FileWriter writes data back out
Figure 12.1 — Wrapping a raw file stream in a buffered reader/writer for efficient I/O.

💡 Placement & Interview Deep-Dive

The Beauty of Try-With-Resources (Java 7+): Any class implementing java.lang.AutoCloseable can be declared inside the try(...) parenthesis. When the block completes (normally or via exception), the JVM automatically calls close(), completely preventing native resource leaks.

12.2 Interfaces and Packages

Packages group related classes and interfaces into modular namespaces (e.g. java.util or com.company.project), preventing class-naming collisions between third-party libraries.

Interfaces allow completely unrelated classes to be treated polymorphically through a shared capability contract:

interface Payable {
    void pay(double amt);
}

class Invoice implements Payable {
    public void pay(double amt) {
        System.out.println("Processing invoice: $" + amt);
    }
}
interface Payable { void pay(double amt); } implements class Invoice implements Payable { public void pay (double amt) {...} }
Figure 12.2 — A class agrees to an interface's contract via 'implements'.

12.3 Generics

Introduced in Java 5, Generics enable classes, interfaces, and methods to operate on parameterized types. They provide compile-time type safety and eliminate the risk of runtime ClassCastException.

class Box<T> {
    private T item;
    void set(T item) { this.item = item; }
    T get() { return item; }
}

Box<String> b = new Box<>();
b.set("hello"); // Type checked at compile time; only Strings allowed!

💡 Placement & Interview Deep-Dive

  • What is Type Erasure in Java? To maintain backward compatibility with pre-Java 5 bytecode, the Java compiler uses Type Erasure: it strips out all generic type information at compile-time, replacing type variables with their bound (or Object), and inserts automatic casts. At runtime, the JVM has no knowledge of generic types!
  • Wildcards & The PECS Principle:
    • <? extends T>: Upper-bounded wildcard. Use when you only Produce items from a collection (Read-Only).
    • <? super T>: Lower-bounded wildcard. Use when you only Consume items into a collection (Write-Only).
    • PECS: Producer Extends, Consumer Super!

12.4 Lambda Expressions and Streams (Java 8+)

Java 8 revolutionized the language by introducing functional programming constructs: Lambda Expressions and the Stream API.

Lambda Expressions

A lambda expression is an anonymous (unnamed) function that provides an inline implementation of a Functional Interface (an interface with exactly one abstract method, such as Runnable or Comparator):

// Traditional anonymous class:
Runnable r1 = new Runnable() {
    public void run() { System.out.println("Hello"); }
};

// Modern Lambda expression:
Runnable r2 = () -> System.out.println("Hello");

The Stream API

The Stream API allows processing collections in a declarative, pipeline style. A stream pipeline chains lazy intermediate operations (filter, map, sorted) followed by an eager terminal operation (collect, count, reduce):

List<String> names = List.of("Amit", "Neha", "Arun", "Pooja");
long count = names.stream()
                  .filter(name -> name.startsWith("A"))
                  .count();
System.out.println("Names starting with A: " + count); // 2
KEY TERM: Functional interface

An interface with exactly one abstract method — the shape that makes it eligible to be implemented inline with a lambda expression instead of a full, separately-written class. Runnable and Comparator are two common built-in examples.

MODULE COMPREHENSIVE QUIZ

Module 12 Final Quiz

Test your understanding across all 4 topics of this module with interview-grade questions, tricky edge cases, and code output predictions.

Take Module 12 Final Quiz →
Yukti Mascot