The fee splitter that died
Riya writes a small program for the college fest: each team's registration fee is split equally among its members. It works for Robotics and Quiz. Then the Dance team registers with 0 members by mistake, and her screen fills with red text. The last line, “All teams done”, never prints.
Sir, my program just died. Half the screen is red. Did I break Java?
No, Java protected you. 900 divided by 0 has no int answer, so instead of printing a wrong number, the JVM threw an exception: an object that says what went wrong and where.
But why did the whole program stop? Only one team was wrong.
Because nobody caught it. The exception climbed from perHead to splitFee to main, looking for code that could handle it. Nobody could, so the JVM printed that red map, the stack trace, and stopped. Today you learn to read that map.
What is an exception?
An exception is an event during program execution that disrupts the normal flow of instructions. In Java it is represented by an object of class Throwable or one of its subclasses. When an exception is thrown, normal execution stops and the JVM searches the call stack, from the current method back towards main, for a matching handler (a catch block). If none is found, the thread's default handler prints the stack trace and the thread terminates.
An exception is an alarm with a note attached. The note says what went wrong and where. The alarm goes up through every method that is waiting, until someone says “I'll handle this.” If nobody does, the program stops and prints the note.
Words you'll meet in this lesson
catch block that matches the exception's type.Exceptions at a glance
| Root class | java.lang.Throwable. Only Throwables can be thrown or caught. |
|---|---|
| Two branches | Error (serious JVM problems, don't catch) and Exception (problems a program can handle) |
| Unchecked | RuntimeException and its subclasses, plus all Errors. The compiler does not force you to handle them. |
| Checked | Every other Exception (e.g. IOException). Must be caught or declared (Lesson 9.3). |
| Useful methods | getMessage(), toString(), printStackTrace(), getStackTrace(), getCause() |
| If uncaught | Stack trace printed to the error stream; the thread ends. For main, the program exits with status 1. |
Exam tip: “Exception” and “Error” are both subclasses of Throwable, but Error is not a subclass of Exception. So catch (Exception e) does not catch a StackOverflowError. A favourite MCQ.
The exception family tree
Error
The JVM itself is in trouble: StackOverflowError, OutOfMemoryError. Your program usually cannot fix these. Don't catch them.
Checked exceptions
Problems outside your code's control: a missing file (IOException), a failed database call (SQLException). The compiler makes you deal with them.
RuntimeException
Usually a bug or bad input: divide by zero, a null reference, a wrong index, text that isn't a number. Fix the code or validate the input.
UncheckedObject
└─ Throwable
├─ Error
│ └─ VirtualMachineError → StackOverflowError, OutOfMemoryError
└─ Exception
├─ IOException → FileNotFoundException (checked)
├─ InterruptedException, SQLException … (checked)
└─ RuntimeException (unchecked)
├─ ArithmeticException
├─ NullPointerException
├─ ClassCastException
├─ IllegalArgumentException → NumberFormatException
└─ IndexOutOfBoundsException → ArrayIndexOutOfBoundsException,
StringIndexOutOfBoundsExceptionSix common exceptions and their real messages
public class Main {
static String coupon; // never set, so it is null
static void trigger(int n) {
int[] seats = new int[3];
Object amount = "500";
switch (n) {
case 1 -> System.out.println(10 / 0);
case 2 -> System.out.println(seats[3]);
case 3 -> System.out.println(coupon.length());
case 4 -> System.out.println(Integer.parseInt("12O"));
case 5 -> System.out.println((Integer) amount);
case 6 -> System.out.println("UPI".charAt(5));
}
}
public static void main(String[] args) {
for (int n = 1; n <= 6; n++) {
try {
trigger(n);
} catch (RuntimeException e) {
System.out.println(e);
}
}
}
}The try/catch in main lets the loop continue after each failure; you'll learn it properly in Lesson 9.2. The arrow-style switch needs Java 14 or later. Messages shown are from Java 21; older versions word some of them differently (detailed NullPointerException messages arrived in Java 14).
| Exception | Typical cause | How to prevent it |
|---|---|---|
ArithmeticException | Integer division or % by zero | Check the divisor first |
ArrayIndexOutOfBoundsException | Index < 0 or ≥ length | Loop with i < a.length; validate indexes |
NullPointerException | Calling a method or reading a field on null | Initialise variables; check for null |
NumberFormatException | Parsing text that isn't a valid number | Validate or trim input; catch and show a message |
ClassCastException | Casting an object to a class it isn't | Check with instanceof before casting |
StringIndexOutOfBoundsException | Bad index in charAt, substring | Check length() first |
Not everything is an exception: 10.0 / 0 gives Infinity and 0.0 / 0 gives NaN. Only integer division by zero throws ArithmeticException. Floating-point maths follows the IEEE 754 rules and never throws for this.
What the JVM does when something goes wrong
An illegal operation happens
Thereturn fee / members; // members is 0idivbytecode instruction finds a zero divisor. Instead of producing a value, the JVM creates anArithmeticExceptionobject on the heap and fills in its message (“/ by zero”) and the current call stack.Normal flow stops at once
The rest of the line, and every line after it in that method, is skipped. There is no return value.
The JVM never moves to the next instruction. Control will jump to a handler, wherever one is found.Look for a handler in the current method
Every compiled method has an exception table (see it withtry { … } catch (ArithmeticException e) { … }javap -c): rows of “from, to, handler, type”. The JVM checks whether the failing instruction lies in a protected range and whether the type matches, including parent classes.No handler? Pop the frame and try the caller
This is called propagation or stack unwinding. Local variables of popped frames are gone; the exception object itself stays on the heap, carrying the information.perHeadhas no catch, so its frame is removed and the search moves tosplitFee, thenmain.Nobody catches it: the stack trace
Read it like this: line 1 = which exception and why (the message). Then theException in thread "main" java.lang.NumberFormatException: For input string: "1,200" at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67) at java.base/java.lang.Integer.parseInt(Integer.java:662) at java.base/java.lang.Integer.parseInt(Integer.java:778) at Main.parseAmount(Main.java:3) at Main.main(Main.java:10)atlines, newest call first. Skip thejava.base/…library lines and find the first line from your own code:parseAmount, line 3, called frommain, line 10. Library line numbers differ between JDK versions.
An exception climbs the call stack: both views
Left: the line being run and the console. Right: the frames on the stack and the exception object on the heap.
ArithmeticException in the fee splitter 6 steps- Call: the Robotics line already printed. Now
maincallssplitFee("Dance", 900, 0). - Deeper:
splitFeecallsperHead(900, 0). Three methods are now waiting on each other. - Throw: integer division by zero has no answer, so the JVM throws an
ArithmeticException. The return never happens. - Skip: neither
perHeadnorsplitFeehas a catch, so the rest of their code is skipped, including the println. - Still nobody:
mainhas no catch either. The loop over the remaining teams and the final message are skipped. - Crash: the JVM's default handler prints the exception and the stack trace, then the program ends.
main's frame holds the loop variable; it is paused at the call tosplitFee, whose frame sits on top.- Calling
perHeadpushes a third frame withfee = 900,members = 0. - The division fails. The JVM creates exception object #1 on the heap with the message and a snapshot of the three frames. That snapshot is the stack trace.
- The JVM checks perHead's exception table: no matching handler. The frame is popped and the search continues in
splitFee. splitFeeand thenmainhave no handler either, so their frames are popped too.- The exception reached the top of the thread with no handler. The default handler prints
toString()plus the recorded trace and the thread terminates.
Exceptions in real systems
Every production Java system deals with exceptions every day. What matters is that they are caught at the right place, logged with their stack trace, and turned into something useful for the user.
Watch it with an example: a batch job that survives a bad record
A nightly job imports 5 student fee records. One row has text instead of a number. With the try/catch inside the loop, one bad row doesn't stop the other four.
- The job: read each line, convert the amount with
Integer.parseInt, save it. Row 103 has the text N/A instead of an amount. - Row 101: parsed and saved.
- Row 102: saved.
- Row 103:
parseInt("N/A")throwsNumberFormatException. Java stops that iteration and jumps to thecatchblock, which logs the row. - Keep going: because the try/catch is inside the loop, the loop simply moves to row 104.
- Result: 4 rows imported and one clear error in the log. Without the catch, the exception would end the whole job at row 103 and rows 104–105 would never load.
1. Logs and alerts
Servers write every unexpected exception, with its full stack trace, to log files. Monitoring tools group errors by exception type and top frame, and alert the on-call engineer when one suddenly increases.
2. Web APIs keep serving
When code handling one request throws, the web framework catches it at the top, returns an error response (like HTTP 500 or 400) to that one user, and keeps serving everyone else.
3. Batch jobs that survive bad records
A nightly job importing 1 lakh rows should not die on row 4,512 because one amount is “1,2OO”. It catches the exception for that row, writes it to an error report, and continues.
4. Friendly messages for bad input
A NumberFormatException from a form field becomes “Please enter a valid amount” on screen, instead of a crash or a blank page.
5. Android crash reports
An uncaught exception in an Android app closes the app. Crash-reporting tools collect the stack trace from users' phones so developers can see exactly which line failed.
Examples are simplified. Real systems use logging libraries and frameworks that catch exceptions at the top level; the idea of a handler higher up the call stack is the same.
Riya's fee splitter, now surviving the bad team
public class Main {
static int perHead(int fee, int members) {
return fee / members;
}
static void splitFee(String team, int fee, int members) {
int share = perHead(fee, members);
System.out.println(team + " pays Rs " + share + " each");
}
public static void main(String[] args) {
String[] teams = {"Robotics", "Dance", "Quiz"};
int[] fees = {1200, 900, 600};
int[] members = {4, 0, 3};
for (int i = 0; i < teams.length; i++) {
try {
splitFee(teams[i], fees[i], members[i]);
} catch (ArithmeticException e) {
System.out.println(teams[i] + " skipped. Stack trace:");
e.printStackTrace(System.out);
}
}
System.out.println("All teams done");
}
}return fee / members;The exception is thrown here, two frames abovemain.try { splitFee(…); }Protects the call. If anything inside, however deep, throws an ArithmeticException, control jumps to the catch.e.printStackTrace(System.out)Prints the same trace the JVM would print on a crash. Without an argument it goes toSystem.err.All teams donePrints because the exception was handled. Compare with the crash in the story.
Follow the exception from perHead to main
Watch the stack grow to three frames, then shrink as the exception travels down to main's catch block. The exception object appears on the heap.
Worked examples: real problems, solved and traced in memory
Three small programs where something goes wrong deep inside a method call. Run each one, then step through it and watch the exception object appear on the heap while the JVM pops frames off the stack until it reaches a method that can handle it.
Average marks for an empty section
Problem statement
A results portal prints the average marks of each section. Section FY-B has no marks uploaded yet, so its array is empty. Show what happens when average divides by the array length 0, and keep the portal running.
FY-A marks = {70, 80}
FY-B marks = {} (nothing uploaded)FY-A average: 75 Report failed: / by zero Done
Approach
maincallsprintReport, which callsaverage: three frames on the stack.- For FY-B,
total / marks.lengthis0 / 0in int arithmetic, so the JVM throwsArithmeticException. - Neither
averagenorprintReporthas a handler, so both frames are popped. Thecatchinmainhandles it. - The program then continues after the try/catch and prints
Done.
Solution: run it live
What happens in memory, step by step
Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.
A quantity typed as a word
Problem statement
A shopping cart lets customers type the quantity. One customer types two instead of 2. Integer.parseInt fails inside a helper two calls deep. Catch the problem in main and tell the customer what to fix.
first item quantity = "2" second item quantity = "two"
Added 2 x Notebook Please enter digits only. For input string: "two" Items in cart: 2
Approach
addToCartasksparseQtyto turn the text into an int.Integer.parseInt("two")creates aNumberFormatExceptionwith the messageFor input string: "two"and throws it.- The exception skips the rest of
parseQtyandaddToCart(their frames are popped) and lands inmain's catch block. - The cart total printed at the end shows only the item that was really added.
Solution: run it live
What happens in memory, step by step
Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.
Which family does the error belong to?
Problem statement
A bus booking app reads the passenger name for a seat number. Seat 7 does not exist on a 4-seat sample bus. Catch the problem as a general RuntimeException in main, then find out its exact class and which branch of the hierarchy it belongs to.
passengers = {"Asha", "Ravi", "Meena", "Imran"}
seat asked = 7Class: ArrayIndexOutOfBoundsException IndexOutOfBounds family? true Unchecked? true
Approach
maincallsdescribeSeat, which callspassengerAt; the bad index is used in the innermost method.- The JVM throws
ArrayIndexOutOfBoundsException. Because it is a subclass ofRuntimeException, acatch (RuntimeException e)inmaincan handle it. e.getClass().getSimpleName()reveals the real class, andinstanceofchecks show its parents in the hierarchy.
Solution: run it live
What happens in memory, step by step
Recorded from the real JVM: press Next to execute one line at a time. Watch method calls push and pop frames on the stack, and objects (numbered #1, #2 …) appear on the heap.
Check yourself
Quick revision
Lesson 9.1 in one screen
- An exception is an object describing a problem; throwing it stops normal flow.
- The JVM searches for a handler in the current method, then pops the frame and tries the caller.
- No handler anywhere → default handler prints the stack trace and the thread ends (exit code 1 for main).
- Stack trace: line 1 = type and message;
atlines newest first; find the first line from your code. Throwable→Error(don't catch) andException.RuntimeExceptionand subclasses are unchecked; other Exceptions are checked.- Common: ArithmeticException, NullPointerException, ArrayIndexOutOfBounds, NumberFormatException, ClassCastException.
Interview and viva questions
What is the difference between an Error and an Exception?
Both extend Throwable. An Error signals a serious problem in the JVM or environment, such as running out of memory or stack space, that an application normally should not try to catch. An Exception signals a condition the program can reasonably handle, such as bad input or a missing file.
What happens internally when an exception is thrown?
The JVM creates the exception object (recording the stack trace), stops normal execution, and looks up the current method's exception table for a handler covering that instruction and matching the type. If none matches, it pops the frame and repeats in the caller. If the stack is exhausted, the thread's uncaught-exception handler prints the trace and the thread terminates.
What is a stack trace and how do you use it?
It is the list of method calls that were active when the exception was created, newest first, with file names and line numbers. Read the first line for the type and message, then go down to the first frame from your own code: that is usually where to start debugging. A “Caused by:” section further down shows the original exception if one was wrapped.
What is the difference between getMessage(), toString() and printStackTrace()?
getMessage() returns only the detail text (can be null). toString() returns the class name plus ": " + message when there is one. printStackTrace() prints toString() followed by every at line, to System.err by default.
Should you catch Throwable or Error?
Almost never. Errors like OutOfMemoryError mean the JVM may be in a bad state, and catching Throwable also hides programming bugs. Catch the specific exceptions you can handle; let a top-level framework handler log anything unexpected.
Practice problems
These problems train you to predict which exception a line throws, read what it tells you, and keep a program running when one item is bad. A small try/catch is used to catch the exception (Lesson 9.2 covers it fully). The last three are real business tasks.
Safe division
Divide 100 by each number in an array. When the number is 0, print a friendly message with the exception's message instead of crashing.
divisors = {4, 0, 5}100 / 4 = 25 100 / 0 failed: / by zero 100 / 5 = 20
Show solution and explanation
public class Main {
public static void main(String[] args) {
int[] divisors = {4, 0, 5};
for (int d : divisors) {
try {
System.out.println("100 / " + d + " = " + (100 / d));
} catch (ArithmeticException e) {
System.out.println("100 / " + d + " failed: " + e.getMessage());
}
}
}
}How it works: the try is inside the loop, so only the turn with 0 fails; the loop carries on with 5. getMessage() returns the text the JVM attached to the exception, here / by zero. If the try were outside the loop, the first 0 would end the whole loop.
Name and message of an exception
Trigger an ArrayIndexOutOfBoundsException, catch it, and print its simple class name, its message, and its full toString().
int[] seats = new int[2]; read seats[2]
Class: ArrayIndexOutOfBoundsException Message: Index 2 out of bounds for length 2 toString: java.lang.ArrayIndexOutOfBoundsException: Index 2 out of bounds for length 2
Show solution and explanation
public class Main {
public static void main(String[] args) {
int[] seats = new int[2];
try {
System.out.println(seats[2]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Class: " + e.getClass().getSimpleName());
System.out.println("Message: " + e.getMessage());
System.out.println("toString: " + e);
}
}
}How it works: every exception is an object, so it has a class and fields. getMessage() gives only the detail text. toString() (used when you print e) gives the full class name, a colon and the message. That is exactly the first line of a stack trace.
Count valid marks
Marks arrive as text. Convert each one with Integer.parseInt, add up the valid ones, and count the entries that are not numbers.
entries = {"78", "9O", "85", "", "64"}Skipped: For input string: "9O" Skipped: For input string: "" Total of valid marks: 227 Invalid entries: 2
Show solution and explanation
public class Main {
public static void main(String[] args) {
String[] entries = {"78", "9O", "85", "", "64"};
int total = 0, bad = 0;
for (String s : entries) {
try {
total += Integer.parseInt(s);
} catch (NumberFormatException e) {
bad++;
System.out.println("Skipped: " + e.getMessage());
}
}
System.out.println("Total of valid marks: " + total);
System.out.println("Invalid entries: " + bad);
}
}How it works: "9O" has the letter O instead of zero, and "" is empty; both make parseInt throw NumberFormatException. When it is thrown, total += … never happens, so a bad entry adds nothing. The message shows the exact input, which makes such bugs easy to find.
Which family is it?
For each exception object, print whether it is a RuntimeException (unchecked), another Exception (checked) or an Error.
ArithmeticException, IOException, StackOverflowError, NumberFormatException, InterruptedException
ArithmeticException -> RuntimeException (unchecked) IOException -> Exception (checked) StackOverflowError -> Error NumberFormatException -> RuntimeException (unchecked) InterruptedException -> Exception (checked)
Show solution and explanation
public class Main {
static String family(Throwable t) {
if (t instanceof Error) return "Error";
if (t instanceof RuntimeException) return "RuntimeException (unchecked)";
return "Exception (checked)";
}
public static void main(String[] args) {
Throwable[] samples = {
new ArithmeticException(),
new java.io.IOException(),
new StackOverflowError(),
new NumberFormatException(),
new InterruptedException()
};
for (Throwable t : samples) {
System.out.println(t.getClass().getSimpleName() + " -> " + family(t));
}
}
}How it works: exceptions are ordinary objects, so you can create them with new without throwing them. instanceof checks the class hierarchy: NumberFormatException extends IllegalArgumentException, which extends RuntimeException. The order of the checks matters: test Error and RuntimeException first, because everything else that is left is a checked exception.
Read the stack trace in code
A method three calls deep divides by zero. Catch the exception in main and print each stack trace entry: the method name and line number, from the top of the stack down.
main → billing → tax → 500 / 0
java.lang.ArithmeticException: / by zero in tax() at line 3 in billing() at line 7 in main() at line 12
Show solution and explanation
public class Main {
static int tax(int amount, int slab) {
return amount / slab;
}
static int billing(int amount) {
return amount + tax(amount, 0);
}
public static void main(String[] args) {
try {
billing(500);
} catch (ArithmeticException e) {
System.out.println(e);
for (StackTraceElement el : e.getStackTrace()) {
System.out.println(" in " + el.getMethodName() + "() at line " + el.getLineNumber());
}
}
}
}How it works: when an exception object is created, the JVM records the call stack at that moment. getStackTrace() returns it as an array: index 0 is where it was thrown (tax, line 3), the last entry is main. This is the same list that printStackTrace() prints, one at … line per entry.
Check first, or catch?
Read a seat number from an array of booked seats in two ways: once by checking the index before reading, once by catching the exception. Both should print the same messages.
booked = {12, 15, 21}, positions 1 and 5seat 15 | seat 15 no seat at position 5 | no seat at position 5
Show solution and explanation
public class Main {
static String byCheck(int[] booked, int pos) {
if (pos < 0 || pos >= booked.length) return "no seat at position " + pos;
return "seat " + booked[pos];
}
static String byCatch(int[] booked, int pos) {
try {
return "seat " + booked[pos];
} catch (ArrayIndexOutOfBoundsException e) {
return "no seat at position " + pos;
}
}
public static void main(String[] args) {
int[] booked = {12, 15, 21};
System.out.println(byCheck(booked, 1) + " | " + byCatch(booked, 1));
System.out.println(byCheck(booked, 5) + " | " + byCatch(booked, 5));
}
}How it works: both give the same answer, but the check is the better habit. An index that can be wrong is an expected situation, and an if is clearer and cheaper than creating an exception object with a stack trace. Keep exceptions for situations you cannot check in advance, such as a file disappearing or a network failing.
Count exceptions by type
Run a list of risky operations on text values and count how many raised NumberFormatException, how many raised StringIndexOutOfBoundsException, and how many succeeded.
codes = {"120", "AB", "7"}; for each: parse it, then read charAt(1)120: value 120, second digit 2 AB: java.lang.NumberFormatException: For input string: "AB" 7: java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1 ok=1, notNumber=1, tooShort=1
Show solution and explanation
public class Main {
public static void main(String[] args) {
String[] codes = {"120", "AB", "7"};
int ok = 0, notNumber = 0, tooShort = 0;
for (String c : codes) {
try {
int value = Integer.parseInt(c);
char second = c.charAt(1);
System.out.println(c + ": value " + value + ", second digit " + second);
ok++;
} catch (NumberFormatException e) {
notNumber++;
System.out.println(c + ": " + e);
} catch (StringIndexOutOfBoundsException e) {
tooShort++;
System.out.println(c + ": " + e);
}
}
System.out.println("ok=" + ok + ", notNumber=" + notNumber + ", tooShort=" + tooShort);
}
}How it works: "AB" fails at parseInt, so charAt is never reached. "7" parses, but has no index 1. Each kind of problem is a different exception class, so each lands in its own catch block. The message format shown is Java 21's; older versions word the index message differently.
Where did the null come from?
A lookup method returns null for an unknown city. Calling a method on that result throws NullPointerException. Catch it and print its message, then fix the call with a null check.
cities known: "Pune" → "411001"; look up "Nagpur"
Cannot invoke "String.length()" because the return value of "Main.pinFor(String)" is null PIN not found
Show solution and explanation
public class Main {
static String pinFor(String city) {
if (city.equals("Pune")) return "411001";
return null;
}
public static void main(String[] args) {
try {
System.out.println(pinFor("Nagpur").length());
} catch (NullPointerException e) {
System.out.println(e.getMessage());
}
String pin = pinFor("Nagpur");
System.out.println(pin == null ? "PIN not found" : "PIN length " + pin.length());
}
}How it works: since Java 14, NullPointerException messages say exactly which value was null; here, the return value of Main.pinFor(String). That points straight at the method that returned null. The second version checks for null first, which is the real fix.
Fest fee splitter
Each team's fee is split equally among its members. One team has registered with 0 members. Print each team's share, mark the broken team, and print how many teams were processed successfully.
teams = {"Robotics", "Dance", "Quiz"}
fees = {1200, 900, 600}, members = {4, 0, 3}Robotics: Rs 300 each Dance: cannot split (/ by zero), check registration Quiz: Rs 200 each 2 of 3 teams processed
Show solution and explanation
public class Main {
static int perHead(int fee, int members) {
return fee / members;
}
public static void main(String[] args) {
String[] teams = {"Robotics", "Dance", "Quiz"};
int[] fees = {1200, 900, 600};
int[] members = {4, 0, 3};
int done = 0;
for (int i = 0; i < teams.length; i++) {
try {
System.out.println(teams[i] + ": Rs " + perHead(fees[i], members[i]) + " each");
done++;
} catch (ArithmeticException e) {
System.out.println(teams[i] + ": cannot split (" + e.getMessage() + "), check registration");
}
}
System.out.println(done + " of " + teams.length + " teams processed");
}
}How it works:
- The exception is thrown inside
perHead, but caught inmain: it travels up one frame to find the handler. - Because the try is per team, one bad registration does not stop the others.
done++sits after the risky call, so it only counts teams that really succeeded.
Amounts from bank SMS alerts
An expense tracker reads the amount part of bank SMS alerts. Some are malformed. Add up the valid debits, list the bad ones with the reason, and print the total in rupees.
amounts = {"1250", "499.00", "Rs 300", "75", "2,000"}Rejected "Rs 300": For input string: "Rs 300" Rejected "2,000": For input string: "2,000" Total spent: Rs 1824.00 (2 rejected)
Show solution and explanation
public class Main {
public static void main(String[] args) {
String[] amounts = {"1250", "499.00", "Rs 300", "75", "2,000"};
double total = 0;
int rejected = 0;
for (String a : amounts) {
try {
total += Double.parseDouble(a);
} catch (NumberFormatException e) {
rejected++;
System.out.println("Rejected \"" + a + "\": " + e.getMessage());
}
}
System.out.printf("Total spent: Rs %.2f (%d rejected)%n", total, rejected);
}
}How it works:
Double.parseDoubleaccepts"499.00"but not text with a currency word or a comma separator; both throwNumberFormatException.- Rejected lines are counted and printed, never silently ignored, so someone can fix the parser for those formats.
- In real money code you would use
BigDecimalor paise in along;doublekeeps this example short.
Warehouse bin lookup
A picker app looks up product names by bin number. Some bins are out of range and one bin is empty (null). For each order line, print the product name in capitals or a clear reason why it could not be found.
bins = {"Rice 5kg", null, "Atta 10kg"}
order bin numbers = {0, 1, 4, 2}Bin 0: RICE 5KG Bin 1: bin is empty Bin 4: no such bin (Index 4 out of bounds for length 3) Bin 2: ATTA 10KG
Show solution and explanation
public class Main {
static String pick(String[] bins, int bin) {
return bins[bin].toUpperCase();
}
public static void main(String[] args) {
String[] bins = {"Rice 5kg", null, "Atta 10kg"};
int[] order = {0, 1, 4, 2};
for (int bin : order) {
try {
System.out.println("Bin " + bin + ": " + pick(bins, bin));
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("Bin " + bin + ": no such bin (" + e.getMessage() + ")");
} catch (NullPointerException e) {
System.out.println("Bin " + bin + ": bin is empty");
}
}
}
}How it works:
- Bin 1 holds
null, sobins[1].toUpperCase()throwsNullPointerException. - Bin 4 does not exist, so
bins[4]throwsArrayIndexOutOfBoundsExceptionbeforetoUpperCaseis even reached. - Both are thrown inside
pickand caught one frame up inmain, each by its owncatch. In production code you would check the index and the null first; this exercise is about recognising the two exceptions.
Real-world scenario questions (asked in company interviews)
Interviewers love giving you a real stack trace or a crash report and asking what you would do. Decide your answer first, then open the model answer.
Reading a stack trace from a support ticket
A support ticket contains this: java.lang.NumberFormatException: For input string: "1,499", followed by six at java.base/… lines, then at com.shop.cart.PriceParser.parse(PriceParser.java:22) and at com.shop.cart.CartService.addItem(CartService.java:58). Where do you start, and what is the likely bug?
The interviewer is checking: can you read a trace quickly and connect the message to the cause?
Show a strong answer
- The message gives the cause: the text
"1,499"contains a comma, whichInteger.parseIntdoes not accept. - Skip the library frames; the first frame from our code is
PriceParser.parse, line 22. That's where the parse call is.CartService.addItemline 58 called it. - Fix: parse prices in a locale-aware way or strip separators before parsing, validate the input, and add a test for
"1,499".
Avoid: starting at the bottom of the trace, or wrapping the call in a catch that hides the error.
One bad row stops the whole interest run
A nightly job calculates interest for 2 lakh savings accounts in one loop. Last night it stopped at account 61,204 with a NullPointerException, and the remaining accounts got no interest. The manager asks why one account affected everyone, and how to prevent it.
The interviewer is checking: do you understand propagation and where to place a handler?
Show a strong answer
- The exception was not caught inside the loop, so it propagated out of the loop and out of the job's main method, ending the whole run.
- Catch exceptions per account inside the loop, log the account number with the stack trace, add it to a failure list, and continue.
- Also fix the root cause (which field was null) and make the job restartable so it can resume from where it stopped.
- Alert if the failure count is above a threshold, because many failures usually mean a systemic bug, not bad data.
Avoid: an empty catch that silently skips accounts. Customers would quietly miss interest.
“Just catch Exception everywhere”
A teammate's checkout code wraps every method body in try { … } catch (Exception e) { } with nothing inside the catch, “so the site never crashes.” Orders are now sometimes saved without a payment record and nobody knows why. What's wrong?
The interviewer is checking: do you know that swallowing exceptions hides bugs and corrupts data?
Show a strong answer
- An empty catch throws away the exception and its stack trace. The failure still happened; we just can't see it, and the code carries on as if it succeeded.
- Catch only exceptions you can really handle, at a level that can decide what to do (retry, show a message, cancel the order).
- Anything else should propagate to a top-level handler that logs it and returns an error, so the order is not half-saved.
Avoid: believing that “no crash” means “no bug”.
StackOverflowError after a new release
After a release, the reports service fails with java.lang.StackOverflowError. The trace shows the same two lines repeating hundreds of times: Category.getFullPath calling Category.getFullPath. A junior suggests adding catch (Exception e) around the call. What do you say?
The interviewer is checking: do you know the Error/Exception split and how to read a repeating trace?
Show a strong answer
StackOverflowErroris anError, not anException, so that catch would not even catch it, and it shouldn't.- The repeating frames mean unbounded recursion: each call pushes a frame until the thread's stack is full. Likely the new data has a cycle (a category whose parent chain loops back to itself) or the base case is missing.
- Fix the recursion: add a correct stop condition, detect cycles with a visited set, or use a loop. Add a data check that prevents cyclic parents.
Avoid: increasing the stack size with -Xss as the fix. An infinite recursion will still overflow.