TD2 — Collections & Exception Handling
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
ArrayListandHashMapwith theVoitureclass 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>withHashMap. - For
listAll(), sort the keys:List<String> keys = new ArrayList<>(map.keySet()); Collections.sort(keys); - For
loadFromFile(), parse each line withline.split(",", 2)and createnew 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 |