JavaIntermediate

Java OOP & Collections: Inheritance, Generics & Exceptions

Go beyond basics: inheritance and interfaces, the Collections Framework in depth, generic type safety, and structured exception handling for production-quality code.

4 sections · ~32 min · 5-question quiz (pass ≥ 70%)

1Inheritance, Abstract Classes, and Interfaces

Inheritance (extends) models "is-a" relationships. A subclass inherits fields and methods from its parent and can override behavior:

public abstract class Shape {
    public abstract double area();

    public void describe() {
        System.out.println("I am a shape with area " + area());
    }
}

public class Circle extends Shape {
    private final double radius;

    public Circle(double radius) { this.radius = radius; }

    @Override
    public double area() {
        return Math.PI * radius * radius;
    }
}

An interface defines a contract — method signatures without implementation (pre-Java 8). A class implements one or more interfaces:

public interface Persistable {
    void save();
    void delete();
}

public class User implements Persistable {
    public void save() { /* write to DB */ }
    public void delete() { /* remove from DB */ }
}

Rules of thumb:

  • Favor composition ("has-a") over deep inheritance hierarchies.
  • Use abstract classes when subclasses share state or partial implementation; use interfaces for capabilities and cross-cutting contracts.
  • Java allows single inheritance of classes but multiple interface implementation.

2The Collections Framework: Lists, Sets, and Maps

The Collections Framework gives you battle-tested data structures with a uniform API.

Need Interface Common impl Notes
Ordered, duplicates OK List ArrayList Random access is O(1)
Unique elements Set HashSet O(1) add/contains
Key–value pairs Map HashMap O(1) get/put average
Map<String, Integer> wordCounts = new HashMap<>();
for (String word : words) {
    wordCounts.merge(word, 1, Integer::sum);
}

List<String> sorted = new ArrayList<>(wordCounts.keySet());
Collections.sort(sorted);

LinkedHashMap preserves insertion order; TreeMap keeps keys sorted. Pick the implementation based on access patterns, not habit.

Unmodifiable views (List.copyOf, Collections.unmodifiableList) let you expose read-only snapshots without letting callers mutate internal state.

3Generics: Type Safety Without Casting

Before generics, every collection held Object and required casts at read time — a runtime ClassCastException waiting to happen. Generics push type checks to compile time.

List<String> names = new ArrayList<>();
names.add("Ada");
// names.add(42);        // compile error — caught immediately
String first = names.get(0); // no cast needed

public static <T> T firstOrNull(List<T> list) {
    return list.isEmpty() ? null : list.get(0);
}

Bounded type parameters restrict what T can be:

public static <T extends Comparable<T>> T max(T a, T b) {
    return a.compareTo(b) >= 0 ? a : b;
}

Wildcards add flexibility at API boundaries:

  • List<?> — read-only unknown type
  • List<? extends Number> — upper bound (producer)
  • List<? super Integer> — lower bound (consumer)

Remember PECS: Producer extends, Consumer super.

4Exceptions: Checked, Unchecked, and Best Practices

Java splits exceptions into two families:

  • Checked (IOException, SQLException) — the compiler forces you to handle or declare them.
  • Unchecked (RuntimeException and subclasses like IllegalArgumentException) — programming errors; no compile-time handling required.
public User findUser(String id) throws UserNotFoundException {
    return repo.findById(id)
        .orElseThrow(() -> new UserNotFoundException(id));
}

try (InputStream in = Files.newInputStream(path)) {
    return parse(in);
} catch (IOException e) {
    throw new DataLoadException("Failed to read " + path, e);
}

Rules of thumb:

  • Throw specific exceptions with context — "User 42 not found" beats a bare Exception.
  • Use try-with-resources for anything implementing AutoCloseable — streams and connections close automatically.
  • Do not use exceptions for normal control flow — they are expensive and obscure intent.
  • Catch at the layer that can meaningfully recover or translate the error for callers.

Ready to test yourself?

Sign in to take the quiz, track progress, and earn a certificate.

Sign in