Free Handbook · Every example compiled & verified

Errors & Debugging

The 15 Java errors every beginner hits, with the real javac and JVM messages, how to read a stack trace, and the debugger, logging and jshell habits that fix bugs fast.

0 / 142 lessons🔥 0 day streak
ShareXLinkedIn

Module 11 · what you'll be able to do

  • Tell a compile error from a runtime exception at a glance and know where to look for each
  • Read a javac diagnostic (file, line, caret, symbol, location) and a stack trace (type, message, frames, Caused by)
  • Recognise and fix the 15 errors Java beginners hit most, from cannot find symbol to StackOverflowError
  • Debug with breakpoints, stepping and watches instead of guessing, and add logging that helps in production
  • Try an idea in seconds with jshell before putting it in a program
01

Compile errors vs runtime exceptions

Java checks your program twice. First javac, the compiler, reads the whole source file and refuses to produce bytecode if anything is wrong with the grammar or the types. Then the JVM runs the bytecode, and problems that only show up with real data — a null, an index past the end, a division by zero — are thrown as exceptions. The two look different, and knowing which one you have tells you where to look.

Compile error (javac)

  • Nothing runs at all — not even the first line of main
  • Format: Main.java:4: error: message, the source line, a ^ caret
  • Ends with 1 error (and error: compilation failed with java Main.java)
  • Always reproducible: same code, same error

Runtime exception (JVM)

  • The program started, printed some output, then stopped
  • Format: Exception in thread "main" java.lang.XxxException: message
  • Followed by at Class.method(File.java:line) frames
  • Depends on the input: it may work for one value and crash for another

Anatomy of a javac error

text
Main.java:4: error: cannot find symbol
        System.out.println(totl);
                           ^
  symbol:   variable totl
  location: class Main
1 error
error: compilation failed

File and line (Main.java:4), the kind of error, the offending line with a caret under the exact token, extra detail lines, and the error count.

  • Fix the first error first. One missing brace can produce ten follow-on errors; after fixing the first, recompile and many of the rest disappear.
  • Trust the line, then look one line up. For a missing ; or ), javac often notices on the next token, so the real mistake is at the end of the previous line.
  • Read the detail lines. symbol:, location:, required: and found: usually say exactly what is wrong.

Anatomy of a stack trace

text
Exception in thread "main" java.lang.NumberFormatException: For input string: "x"
	at java.base/java.lang.NumberFormatException.forInputString(Unknown Source)
	at java.base/java.lang.Integer.parseInt(Unknown Source)
	at java.base/java.lang.Integer.parseInt(Unknown Source)
	at Main.parse(Main.java:3)
	at Main.total(Main.java:8)
	at Main.main(Main.java:13)

The real trace from the program at the end of this lesson, without its try/catch. Line 1: the exception type and message. Then the call stack, newest call on top. The bottom frame is where the program started.

  1. 1
    Read the first line

    The exception class and its message are often the whole answer: For input string: "x" means someone passed "x" to parseInt.

  2. 2
    Skip the JDK frames

    Frames starting with java.base/ are inside the JDK. The JDK is almost never the bug.

  3. 3
    Find the first frame in your code

    Main.parse(Main.java:3) is where your code made the call that failed. Open that line.

  4. 4
    Read downward to see how you got there

    Each frame below is the caller: total line 8 called parse, and main line 13 called total. The bad value came in through that path.

  5. 5
    If there is a "Caused by", jump to the last one

    Frameworks wrap exceptions. The deepest Caused by: section is the original failure, and its first frame in your code is where to start.

A stack trace is also an object you can inspect. This program catches the exception and prints only the frames that belong to Main, which is exactly the filter your eyes should apply:

javaMain.java
public class Main {
    static int parse(String s) {
        return Integer.parseInt(s);
    }

    static int total(String[] items) {
        int t = 0;
        for (String s : items) t += parse(s);
        return t;
    }
    public static void main(String[] args) {
        try {
            total(new String[] {"4", "x"});
        } catch (NumberFormatException e) {
            System.out.println(e);
            for (StackTraceElement f : e.getStackTrace()) {
                if (f.getClassName().equals("Main")) {
                    System.out.println("  at " + f.getMethodName() + " line " + f.getLineNumber());
                }
            }
        }
    }
}
Outputcompiled & run with real Java
java.lang.NumberFormatException: For input string: "x"
  at parse line 3
  at total line 8
  at main line 13
Your turn

Move the bad value to the first position ({"x", "4"}). Do the frames change? Why not?

02

Compile errors: names, types and static

These three are the errors you will see most in your first months. All of them are the compiler protecting you: it refuses to guess what you meant.

Error you will hit

1. cannot find symbol

java
public class Main {
    public static void main(String[] args) {
        int total = 10;
        System.out.println(totl);
    }
}
Main.java:4: error: cannot find symbol
        System.out.println(totl);
                           ^
  symbol:   variable totl
  location: class Main
1 error
error: compilation failed
Why the compiler said that

javac has no variable, method or class called totl in scope. The usual causes: a typo, wrong capitalisation (string instead of String), a variable declared inside a block and used outside it, or a missing import.

The fix

Read the symbol: line — it names exactly what could not be found — and check spelling, case, scope and imports. Your IDE underlines it in red before you even compile.

java
public class Main {
    public static void main(String[] args) {
        int total = 10;
        System.out.println(total);
    }
}
Error you will hit

2. incompatible types: String cannot be converted to int

java
public class Main {
    public static void main(String[] args) {
        String input = "42";
        int n = input;
        System.out.println(n + 1);
    }
}
Main.java:4: error: incompatible types: String cannot be converted to int
        int n = input;
                ^
1 error
error: compilation failed
Why the compiler said that

Java is statically typed: an int variable can only hold an int. Text that looks like a number is still a String, and Java never converts between the two silently.

The fix

Convert explicitly with Integer.parseInt(input) (and be ready for error 10 below if the text is not a number). The reverse direction is String.valueOf(n).

java
public class Main {
    public static void main(String[] args) {
        String input = "42";
        int n = Integer.parseInt(input);
        System.out.println(n + 1);
    }
}
Error you will hit

3. non-static method cannot be referenced from a static context

java
public class Main {
    int add(int a, int b) {
        return a + b;
    }

    public static void main(String[] args) {
        System.out.println(add(2, 3));
    }
}
Main.java:7: error: non-static method add(int,int) cannot be referenced from a static context
        System.out.println(add(2, 3));
                           ^
1 error
error: compilation failed
Why the compiler said that

main is static: it belongs to the class and runs without any object. add has no static, so it belongs to an instance of Main, and there is no instance to call it on.

The fix

For a helper that uses no instance fields, add static. If the method really needs object state, create the object first: new Main().add(2, 3).

java
public class Main {
    static int add(int a, int b) {
        return a + b;
    }

    public static void main(String[] args) {
        System.out.println(add(2, 3));
    }
}
03

Compile errors: flow and checked exceptions

javac also performs flow analysis: it follows every path through a method and proves that each variable is assigned before use, each non-void method returns, and no statement is dead. It also checks that every checked exception is handled. It does this without running anything, so it only reasons about the code's shape, not the values.

Error you will hit

4. missing return statement

java
public class Main {
    static String grade(int score) {
        if (score >= 50) {
            return "pass";
        } else if (score < 50) {
            return "fail";
        }
    }

    public static void main(String[] args) {
        System.out.println(grade(70));
    }
}
Main.java:8: error: missing return statement
    }
    ^
1 error
error: compilation failed
Why the compiler said that

You know score >= 50 and score < 50 cover every int, but javac does not evaluate conditions. It sees an if / else if with no final else, so there is a path that reaches the closing brace without returning.

The fix

Make the last branch a plain else (or put a return after the if). The caret points at the closing brace because that is where the method falls off the end.

java
public class Main {
    static String grade(int score) {
        if (score >= 50) {
            return "pass";
        } else {
            return "fail";
        }
    }

    public static void main(String[] args) {
        System.out.println(grade(70));
    }
}
Error you will hit

5. unreachable statement

java
public class Main {
    static int square(int x) {
        return x * x;
        System.out.println("squared " + x);
    }

    public static void main(String[] args) {
        System.out.println(square(4));
    }
}
Main.java:4: error: unreachable statement
        System.out.println("squared " + x);
        ^
1 error
error: compilation failed
Why the compiler said that

return leaves the method immediately, so the line after it can never run. Java treats dead code as an error rather than a warning, because it is almost always a mistake. The same happens after break, continue, throw and an infinite while (true).

The fix

Move the statement before the return, or delete it.

java
public class Main {
    static int square(int x) {
        System.out.println("squaring " + x);
        return x * x;
    }

    public static void main(String[] args) {
        System.out.println(square(4));
    }
}
Error you will hit

6. variable might not have been initialized

java
public class Main {
    public static void main(String[] args) {
        int bonus;
        int sales = 120;
        if (sales > 100) {
            bonus = 50;
        }
        System.out.println("Bonus: " + bonus);
    }
}
Main.java:8: error: variable bonus might not have been initialized
        System.out.println("Bonus: " + bonus);
                                       ^
1 error
error: compilation failed
Why the compiler said that

Local variables get no default value (fields do, locals do not). bonus is only assigned when the if is true; on the other path it would hold garbage, so javac refuses. Again, it does not care that sales is 120 right now.

The fix

Assign a value on every path: initialise at the declaration (int bonus = 0;) or add an else.

java
public class Main {
    public static void main(String[] args) {
        int bonus = 0;
        int sales = 120;
        if (sales > 100) {
            bonus = 50;
        }
        System.out.println("Bonus: " + bonus);
    }
}
Error you will hit

7. unreported exception IOException; must be caught or declared to be thrown

java
import java.nio.file.*;

public class Main {
    public static void main(String[] args) {
        String text = Files.readString(Path.of("notes.txt"));
        System.out.println(text);
    }
}
Main.java:5: error: unreported exception IOException; must be caught or declared to be thrown
        String text = Files.readString(Path.of("notes.txt"));
                                      ^
1 error
error: compilation failed
Why the compiler said that

Files.readString declares throws IOException, a checked exception: the file might not exist, might be locked, the disk might fail. Java forces every caller to decide what happens then. (Unchecked exceptions — subclasses of RuntimeException — carry no such rule.)

The fix

Either handle it with try/catch where you can do something useful (show a message, use a default), or add throws IOException to the method signature to pass the decision to the caller.

java
import java.io.IOException;
import java.nio.file.*;

public class Main {
    public static void main(String[] args) {
        try {
            String text = Files.readString(Path.of("notes.txt"));
            System.out.println(text);
        } catch (IOException e) {
            System.out.println("Could not read notes.txt: " + e.getMessage());
        }
    }
}
Let the IDE fix these for you
IntelliJ IDEA, VS Code and Eclipse flag all seven compile errors above as you type, and Alt+Enter (IntelliJ) or Ctrl+. (VS Code) offers the fix: import the class, add static, surround with try/catch, initialise the variable. Read the suggestion before accepting it — "add throws" and "surround with try/catch" are different design choices.
04

Runtime exceptions: null, indexes, casts and parsing

These programs compile cleanly and then fail while running, because a value was not what the code assumed. The fix is rarely a try/catch; it is usually validating the value or correcting the logic that produced it.

Error you will hit

8. NullPointerException (with the helpful message)

java
public class Main {
    record User(String name, String email) {}

    public static void main(String[] args) {
        User u = new User("Ada", null);
        System.out.println(u.email().toLowerCase());
    }
}
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.toLowerCase()" because the return value of "Main$User.email()" is null
	at Main.main(Main.java:6)
Why the compiler said that

You called a method on a reference that points at nothing. Since Java 14 the JVM prints a helpful NullPointerException message that names exactly which expression was null — here the return value of email() — so you no longer have to guess which of several dots on the line failed.

The fix

Find where the null came from (here, the constructor call) and decide: should it be impossible (validate with Objects.requireNonNull at the boundary) or allowed (check for it, or return Optional)?

java
public class Main {
    record User(String name, String email) {}

    public static void main(String[] args) {
        User u = new User("Ada", null);
        String email = u.email() == null ? "(no email)" : u.email().toLowerCase();
        System.out.println(email);
    }
}
Error you will hit

9. ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3

java
public class Main {
    public static void main(String[] args) {
        int[] scores = {90, 75, 60};
        for (int i = 0; i <= scores.length; i++) {
            System.out.println(scores[i]);
        }
    }
}
90
75
60
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
	at Main.main(Main.java:5)
Why the compiler said that

An array of length 3 has indexes 0, 1 and 2. The loop uses <=, so it runs once more with i = 3. This is the classic off-by-one bug. Lists throw the sibling IndexOutOfBoundsException, and strings StringIndexOutOfBoundsException.

The fix

Loop with i < scores.length, or better, use the enhanced for loop and never touch the index at all.

java
public class Main {
    public static void main(String[] args) {
        int[] scores = {90, 75, 60};
        for (int score : scores) {
            System.out.println(score);
        }
    }
}
Error you will hit

10. NumberFormatException: For input string

java
public class Main {
    public static void main(String[] args) {
        String price = "19.99";
        int cents = Integer.parseInt(price);
        System.out.println(cents);
    }
}
Exception in thread "main" java.lang.NumberFormatException: For input string: "19.99"
	at java.base/java.lang.NumberFormatException.forInputString(Unknown Source)
	at java.base/java.lang.Integer.parseInt(Unknown Source)
	at java.base/java.lang.Integer.parseInt(Unknown Source)
	at Main.main(Main.java:4)
Why the compiler said that

Integer.parseInt accepts only an optional sign and digits. A decimal point, a space, a comma, an empty string or "abc" all fail. User input and CSV files are the usual source.

The fix

Use the parser that matches the data (Double.parseDouble, or new BigDecimal(price) for money), strip() whitespace first, and wrap parsing of untrusted input in try/catch (NumberFormatException e).

java
import java.math.BigDecimal;

public class Main {
    public static void main(String[] args) {
        String price = "19.99";
        BigDecimal amount = new BigDecimal(price.strip());
        int cents = amount.movePointRight(2).intValueExact();
        System.out.println(cents);
    }
}
Error you will hit

11. ClassCastException: class String cannot be cast to class Integer

java
public class Main {
    public static void main(String[] args) {
        Object value = "123";
        Integer n = (Integer) value;
        System.out.println(n + 1);
    }
}
Exception in thread "main" java.lang.ClassCastException: class java.lang.String cannot be cast to class java.lang.Integer (java.lang.String and java.lang.Integer are in module java.base of loader 'bootstrap')
	at Main.main(Main.java:4)
Why the compiler said that

A cast does not convert anything; it only tells the compiler "trust me, this object is really an Integer". At runtime the JVM checks, finds a String, and throws. It usually appears when code stores things as Object or uses raw (non-generic) collections.

The fix

Keep types precise with generics so casts are not needed. When you must branch on a type, use pattern matching: if (value instanceof Integer n). And to turn text into a number, parse it — do not cast it.

java
public class Main {
    public static void main(String[] args) {
        Object value = "123";
        if (value instanceof Integer n) {
            System.out.println(n + 1);
        } else if (value instanceof String s) {
            System.out.println(Integer.parseInt(s) + 1);
        }
    }
}
Error you will hit

12. InputMismatchException from Scanner

java
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        System.out.print("Age: ");
        int age = in.nextInt();
        System.out.println("Next year you will be " + (age + 1));
    }
}
Age: Exception in thread "main" java.util.InputMismatchException
	at java.base/java.util.Scanner.throwFor(Unknown Source)
	at java.base/java.util.Scanner.next(Unknown Source)
	at java.base/java.util.Scanner.nextInt(Unknown Source)
	at java.base/java.util.Scanner.nextInt(Unknown Source)
	at Main.main(Main.java:7)
Why the compiler said that

The user typed twenty. nextInt() found a token that is not an integer and threw, with no message at all — you have to recognise the class name. The bad token also stays in the Scanner, so a retry loop that just calls nextInt() again spins forever.

The fix

Check with hasNextInt() before reading, and throw the bad token away with next() when it is not a number.

java
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        System.out.print("Age: ");
        while (!in.hasNextInt()) {
            System.out.print("Please type a whole number: ");
            in.next();                       // discard the bad token
        }
        int age = in.nextInt();
        System.out.println("Next year you will be " + (age + 1));
    }
}
05

Runtime exceptions: collections, arithmetic and recursion

Error you will hit

13. ConcurrentModificationException

java
import java.util.*;

public class Main {
    public static void main(String[] args) {
        List<Integer> nums = new ArrayList<>(List.of(1, 2, 3, 4));
        for (Integer n : nums) {
            if (n % 2 == 0) nums.remove(n);
        }
        System.out.println(nums);
    }
}
Exception in thread "main" java.util.ConcurrentModificationException
	at java.base/java.util.ArrayList$Itr.checkForComodification(Unknown Source)
	at java.base/java.util.ArrayList$Itr.next(Unknown Source)
	at Main.main(Main.java:6)
Why the compiler said that

The for-each loop walks the list with a hidden iterator. Removing from the list directly changes its modification count, and the iterator's next step notices and fails. No threads are involved despite the name. Note the frame points at line 6 (the loop header, where next() is called), not line 7 where the remove happened.

The fix

Use removeIf, remove through an explicit Iterator, or collect what to keep into a new list. See Collections for all three.

java
import java.util.*;

public class Main {
    public static void main(String[] args) {
        List<Integer> nums = new ArrayList<>(List.of(1, 2, 3, 4));
        nums.removeIf(n -> n % 2 == 0);
        System.out.println(nums);
    }
}
Error you will hit

14. ArithmeticException: / by zero

java
public class Main {
    static int average(int total, int count) {
        return total / count;
    }

    public static void main(String[] args) {
        System.out.println(average(300, 3));
        System.out.println(average(0, 0));
    }
}
100
Exception in thread "main" java.lang.ArithmeticException: / by zero
	at Main.average(Main.java:3)
	at Main.main(Main.java:8)
Why the compiler said that

Integer division by zero has no answer, so the JVM throws. Read the two frames: the crash is in average line 3, but the bad argument came from main line 8. (Floating-point division does not throw: 1.0 / 0 is Infinity and 0.0 / 0 is NaN, which is its own kind of bug.)

The fix

Decide what an empty input means for your program and handle it before dividing: return 0, return an OptionalDouble, or throw an IllegalArgumentException with a clear message.

java
public class Main {
    static int average(int total, int count) {
        if (count == 0) return 0;          // no items: define the answer
        return total / count;
    }

    public static void main(String[] args) {
        System.out.println(average(300, 3));
        System.out.println(average(0, 0));
    }
}
Error you will hit

15. StackOverflowError

java
public class Main {
    static int factorial(int n) {
        return n * factorial(n - 1);
    }

    public static void main(String[] args) {
        System.out.println(factorial(5));
    }
}
Exception in thread "main" java.lang.StackOverflowError
	at Main.factorial(Main.java:3)
	at Main.factorial(Main.java:3)
	at Main.factorial(Main.java:3)
	at Main.factorial(Main.java:3)
	... (the same frame, repeated about a thousand more times)
Why the compiler said that

Every method call pushes a frame on the thread's stack. This recursion has no base case, so it calls itself with 5, 4, 3 … 0, -1, -2 … until the stack runs out. A trace full of the same frame is the signature. It is an Error, not an Exception: do not catch it, fix the recursion.

The fix

Add a base case that stops the recursion before the recursive call. If the input is legitimately deep (a long linked list, a huge tree), rewrite the recursion as a loop.

java
public class Main {
    static int factorial(int n) {
        if (n <= 1) return 1;               // base case
        return n * factorial(n - 1);
    }

    public static void main(String[] args) {
        System.out.println(factorial(5));
    }
}
In real jobs
In a Spring or Jakarta service, an uncaught runtime exception becomes an HTTP 500 and a stack trace in the log. The first thing a senior engineer does is scroll to the deepest Caused by:, find the first frame in the team's own package, and open that line. Practise that habit on every trace in this module.
06

Debugger, logging and jshell

Reading the error tells you where the program failed. When it did not crash but gave the wrong answer, you need to see what it was thinking. Java has three tools for that, in order of how often you will use them.

1. The IDE debugger

  1. 1
    Set a breakpoint

    Click the gutter next to a line number. Run with Debug (the bug icon) instead of Run; the program pauses when it reaches that line.

  2. 2
    Inspect

    The Variables panel shows every local and field right now. Hover over any expression, or add it to Watches to track it across steps.

  3. 3
    Step

    Step Over (F8 in IntelliJ) runs the current line. Step Into (F7) enters the method being called. Step Out finishes the current method. Resume runs to the next breakpoint.

  4. 4
    Use conditional breakpoints

    Right-click a breakpoint and add a condition such as i == 999 or name == null to stop only on the iteration that matters.

  5. 5
    Break on exceptions

    An exception breakpoint for NullPointerException pauses at the exact moment it is thrown, with every variable still on screen.

Without an IDE, the JDK ships jdb, a command-line debugger, and every IDE can attach to a JVM started with the debug agent — which is how you debug a server running in Docker.

bash
# start a program so a debugger can attach on port 5005
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 -jar app.jar

# command-line debugger (breakpoint on a method, then run)
jdb -classpath . Main
> stop in Main.average
> run

# a hung program: print every thread and any deadlock
jcmd <pid> Thread.print

2. Print debugging, done properly

A few well-placed prints are a legitimate tool, especially for loops. Print the loop variable and the state together, and let records do the formatting for you. The output below exposes a bug at a glance: the running maximum starts at 0, so an all-negative input reports 0.

javaMain.java
public class Main {
    record Step(int i, int value, int max) {}

    public static void main(String[] args) {
        int[] temps = {-7, -3, -12};
        int max = 0;                          // bug: should start at temps[0]
        for (int i = 0; i < temps.length; i++) {
            if (temps[i] > max) max = temps[i];
            System.out.println(new Step(i, temps[i], max));
        }
        System.out.println("max = " + max);
    }
}
Outputcompiled & run with real Java
Step[i=0, value=-7, max=0]
Step[i=1, value=-3, max=0]
Step[i=2, value=-12, max=0]
max = 0
Your turn

Fix the bug by starting max at temps[0] (or Integer.MIN_VALUE) and check that the answer becomes -3.

3. Logging for code that runs without you

Prints are deleted before commit. Logging stays: it has levels (so debug detail can be switched off in production), timestamps, the thread name, and goes to files or a log platform. The JDK has java.util.logging and System.Logger; real projects almost always use SLF4J with Logback or Log4j 2.

java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class OrderService {
    private static final Logger log = LoggerFactory.getLogger(OrderService.class);

    void place(Order order) {
        log.debug("placing order {} with {} items", order.id(), order.items().size());
        try {
            payments.charge(order);
            log.info("order {} placed", order.id());
        } catch (PaymentException e) {
            log.error("payment failed for order {}", order.id(), e);   // pass e LAST: the stack trace is logged
            throw e;
        }
    }
}

Use {} placeholders instead of string concatenation (the message is only built if that level is enabled), and pass the exception as the final argument so its stack trace is not lost.

jshell: answer "what does this do?" in five seconds

jshell (in every JDK since 9) is a REPL: type an expression, see the value. Use it to check an API before writing a program around it.

text
$ jshell
jshell> Integer.parseInt(" 42".strip())
$1 ==> 42

jshell> "a,b,,c".split(",")
$2 ==> String[4] { "a", "b", "", "c" }

jshell> 7 / 2
$3 ==> 3

jshell> 7 / 2.0
$4 ==> 3.5

jshell> /exit
A debugging routine that works
1. Reproduce it with the smallest input. 2. Read the whole message and find your first frame. 3. Form one guess about the cause. 4. Check it with a breakpoint or a print. 5. Fix, then re-run the original failing case — and add a unit test for it so it never comes back.
07

Index of all 15 errors

Exceptions specific to threads (ExecutionException, IllegalThreadStateException) are covered in Concurrency.
#ErrorKindUsual causeUsual fix
1cannot find symbolCompileTypo, wrong case, out of scope, missing importCheck the symbol: line; import or fix the name
2incompatible typesCompileAssigning a String to an int (or similar)Convert explicitly (parseInt, valueOf)
3non-static … from a static contextCompileCalling an instance method from mainMake it static or create an object
4missing return statementCompileif / else if with no final elseReturn on every path
5unreachable statementCompileCode after return, break, throwMove it before or delete it
6might not have been initializedCompileLocal assigned on only some pathsInitialise at declaration
7unreported exception …CompileCalling a method that throws a checked exceptiontry/catch or throws
8NullPointerExceptionRuntimeMethod call on a null referenceFind the source of null; validate or handle it
9ArrayIndexOutOfBoundsExceptionRuntimeOff-by-one: <= instead of <Use < length or for-each
10NumberFormatExceptionRuntimeParsing text that is not a numberRight parser, strip(), catch on user input
11ClassCastExceptionRuntimeCasting an object to a type it is notGenerics, instanceof patterns
12InputMismatchExceptionRuntimeScanner read a word where a number was expectedhasNextInt() first, discard with next()
13ConcurrentModificationExceptionRuntimeRemoving from a collection inside for-eachremoveIf or Iterator.remove()
14ArithmeticException: / by zeroRuntimeInteger division by zeroGuard the zero case
15StackOverflowErrorRuntimeRecursion with no base caseAdd a base case or use a loop
Compile error
A problem javac finds before anything runs; no bytecode is produced.
Runtime exception
An unchecked exception thrown while the program runs (subclass of RuntimeException).
Checked exception
An exception the compiler forces you to catch or declare, such as IOException.
Stack trace
The exception type, message and the chain of method calls (frames) that led to it, newest first.
Caused by
A wrapped original exception inside a stack trace; the deepest one is the root cause.
Helpful NPE
The Java 14+ NullPointerException message that names the exact null expression.
Breakpoint
A line where the debugger pauses the program so you can inspect variables.
jshell
The JDK's interactive REPL for trying Java expressions.
Quick check

A stack trace shows at java.base/java.lang.Integer.parseInt(Unknown Source) on top, then at Main.load(Main.java:21), then at Main.main(Main.java:5). Which line should you open first?

Quick check

Which of these is reported by javac, before the program runs?

Frequently asked questions

What does "cannot find symbol" mean in Java?
The compiler cannot find a variable, method or class with that name where you used it. Check the "symbol:" line of the message for the exact name, then look for a typo, wrong capitalisation, a variable declared in an inner block, or a missing import.
How do I read a Java stack trace?
Read the first line for the exception type and message, skip the frames that start with java.base/, and open the first frame that names your own class and line. Frames below it show which methods called it. If there is a "Caused by:" section, the deepest one is the original error.
Should I catch NullPointerException?
Almost never. A NullPointerException is a bug report: find where the null came from and either prevent it (validate inputs with Objects.requireNonNull) or handle the absent value explicitly (a null check or Optional). Catching it hides the bug and makes the next failure harder to trace.

Finish the Java handbook, then get hired

Sit the exam for your certificate, run your resume through the ATS checker, and see the jobs that ask for exactly this.

Check my resume
Found this course useful? Share it.
ShareXLinkedIn

Comments

0

Join the conversation. Sign in to leave a comment — we'd love to hear your thoughts.