Skip to content

TD2 — Collections & Exception Handling

← Part 1 Overview

S7 Inf A3 — Java for Graphical and Mobile Programming
Stéphane Derrode — Centrale Lyon
Part 1 — Java Fundamentals
Duration: 2h · Continue the td1 Maven project (or create td2)


Objectives

  • Use ArrayList and HashMap with the Voiture class from TD1
  • Write and throw custom exception classes
  • Persist a fleet to a text file with try-with-resources
  • Implement a stack-based RPN calculator

Part 1 — FleetManager with HashMap (40 min)

1.1 Custom exception

Create src/main/java/com/s7infa3/VoitureNotFoundException.java:

package com.s7infa3;

public class VoitureNotFoundException extends RuntimeException {
    private String owner;

    public VoitureNotFoundException(String owner) {
        super("No vehicle registered for: " + owner);
        this.owner = owner;
    }

    public String getOwner() { return owner; }
}

1.2 Class FleetManager

Create src/main/java/com/s7infa3/FleetManager.java.

Method Description
register(String owner, Voiture v) Registers or replaces a vehicle for the owner
lookup(String owner) Returns the vehicle; throws VoitureNotFoundException if not found
unregister(String owner) Removes the entry; throws VoitureNotFoundException if not found
size() Returns the number of registered vehicles
listAll() Prints all entries sorted alphabetically by owner name
demarrerTout() Calls demarre() on every registered vehicle
saveToFile(String path) Saves as owner,puissance lines; declares throws IOException
loadFromFile(String path) Reloads from file (replaces existing data); declares throws IOException

Hints:

  • Use Map<String, Voiture> with HashMap.
  • For listAll(), sort the keys: List<String> keys = new ArrayList<>(map.keySet()); Collections.sort(keys);
  • For loadFromFile(), parse each line with line.split(",", 2) and create new Voiture(Integer.parseInt(parts[1])).

1.3 Test in main()

FleetManager fm = new FleetManager();
fm.register("Alice", new Voiture(4));
fm.register("Bob",   new Voiture(6));
fm.register("Charlie", new Voiture(28));

System.out.println(fm.lookup("Alice")); // Voiture[p=4, ...]
fm.listAll();   // Alice, Bob, Charlie (sorted)

fm.demarrerTout();
System.out.println(fm.lookup("Bob"));   // Voiture[p=6, demarree=true, ...]

fm.saveToFile("fleet.txt");

FleetManager fm2 = new FleetManager();
fm2.loadFromFile("fleet.txt");
System.out.println(fm2.size());         // 3

// Exception test
try {
    fm.lookup("Dave");
} catch (VoitureNotFoundException e) {
    System.out.println("Caught: " + e.getMessage());
    System.out.println("Owner: "  + e.getOwner());
}

Part 2 — Stack-based RPN Calculator (35 min)

Implement a Reverse Polish Notation (RPN) expression evaluator using Stack<Double>.

How RPN works

In RPN, operators come after their operands:

Infix expression RPN Result
3 + 4 3 4 + 7
(3 + 4) × 2 3 4 + 2 * 14
5 + 1×2 + 4×3 − 3 5 1 2 + 4 * + 3 - 14

Algorithm: scan tokens left to right: - Number → push it - Operator + - * /pop two values, compute, push result - At the end, the single remaining value is the result

2.1 Class RPNCalculator

Create src/main/java/com/s7infa3/RPNCalculator.java.

Method Description
evaluate(String expression) Evaluates a space-separated RPN string, returns double

Throw ArithmeticException("Division by zero") for / with zero divisor.
Throw IllegalArgumentException("Invalid expression") if the stack does not end with exactly one value.

Hint for parsing:

String[] tokens = expression.split("\\s+");
for (String token : tokens) {
    try {
        stack.push(Double.parseDouble(token)); // it's a number
    } catch (NumberFormatException e) {
        // it's an operator
    }
}

2.2 Test

RPNCalculator calc = new RPNCalculator();
System.out.println(calc.evaluate("3 4 +"));           // 7.0
System.out.println(calc.evaluate("3 4 + 2 *"));       // 14.0
System.out.println(calc.evaluate("5 1 2 + 4 * + 3 -")); // 14.0
System.out.println(calc.evaluate("10 2 /"));           // 5.0

try {
    calc.evaluate("10 0 /");
} catch (ArithmeticException e) {
    System.out.println("Caught: " + e.getMessage());   // Division by zero
}

Part 3 — Persistence Integration (15 min)

3.1 Calculator history

Add to RPNCalculator: - A List<String> field history storing each successfully evaluated expression - saveHistory(String path) throws IOException — writes one expression per line - loadHistory(String path) throws IOException — reads and re-evaluates each line, printing the result

3.2 Test

RPNCalculator calc = new RPNCalculator();
calc.evaluate("3 4 +");
calc.evaluate("10 2 /");
calc.saveHistory("history.txt");

RPNCalculator calc2 = new RPNCalculator();
calc2.loadHistory("history.txt");  // prints: 7.0 then 5.0

Part 4 — Exploration (remaining time)

4.1 Add boolean contains(String owner) and int countStarted() (counts vehicles where isEstDemarree() is true) to FleetManager.

4.2 Make loadFromFile() robust: skip malformed lines (not exactly one comma) instead of crashing.

4.3 Extend RPNCalculator to support % (modulo).


Deliverable

No formal submission. Verify all main() outputs match expected values before leaving.


Common Errors

Error Cause Fix
NullPointerException on map.get() Key not present → returns null Use containsKey() or getOrDefault() first
EmptyStackException pop() on empty stack Guard with stack.size() >= 2 before popping
NumberFormatException not caught Token is neither number nor operator Catch it and handle as operator
FileNotFoundException Wrong path File path is relative to project root with Maven