Not all errors are equal. Some mistakes are caught the moment you run javac; others hide until the program is executing. Knowing which is which — and how to read the messages Java gives you — turns frustrating failures into five-second fixes.
The difference matters because your response to each type is completely different. A compile-time error means you broke a language rule, and the compiler is telling you exactly where. A runtime error means your code is structurally valid but logically dangerous, and you need to trace how the data reached that dangerous state. Learning to classify an error in the first five seconds saves you from wandering in the wrong direction for half an hour.
Compile-time errors: caught by javac
A compile-time error means the compiler cannot translate your source into bytecode. It reads your file top to bottom, building a model of what you mean, and the moment it finds something that violates Java's rules it stops and reports the problem.
Common causes include:
- Missing semicolons or mismatched braces
- Using a variable before it is declared
- Assigning the wrong type (
int x = "hello";) - Calling a method that does not exist on a class
- Misspelling a keyword or identifier
These are your friends. They appear immediately, point to a specific line and often a column, and prevent broken code from ever running. The compiler is a safety net that dynamically typed languages lack.
flowchart TD SRC[".java source"] --> JC["javac (compiler)"] JC -->|compile error| CE["Build fails<br/>Error message with line:column"] JC --> CLS[".class bytecode"] CLS --> JVM["JVM executes"] JVM -->|runtime error| RE["Exception thrown<br/>Stack trace printed"] style JC fill:#c2410c,color:#fff style JVM fill:#c2410c,color:#fff style CE fill:#fed7aa style RE fill:#fed7aa
public class Main {
public static void main(String[] args) {
int count = 5
System.out.println("Count: " + count);
}
}
Type errors: the compiler's superpower
Java's static type system means the compiler knows what every variable is allowed to hold. Try to store a String in an int variable and the build fails before you even think about running the program. This catches an entire category of bugs that dynamically typed languages only find when they crash in production.
The error message will say something like incompatible types: String cannot be converted to int. That is precise: it names the two types involved and the direction of the mistake. Learn to read those messages literally rather than guessing, and you will fix type errors in seconds.
public class Main {
public static void main(String[] args) {
int age = "twenty";
System.out.println("Age: " + age);
}
}
Runtime errors: caught by the JVM
A runtime error means the code compiled successfully — it is valid Java — but something goes wrong during execution. The compiler checked the grammar and the types, but it cannot know every value a variable will hold when real data flows through the program.
Common causes include:
- Dividing by zero
- Accessing an array index that does not exist
- Calling a method on a
nullreference - Running out of memory
Unlike a compile error, a runtime error can be intermittent. It might only appear when a user enters zero, or when a file is missing. That unpredictability is what makes runtime bugs expensive. When the JVM detects one, it throws an exception and prints a stack trace: a list of every method that was active, with file names and line numbers.
public class Main {
public static void main(String[] args) {
int a = 10;
int b = 0;
int result = a / b;
System.out.println("Result: " + result);
}
}
flowchart TD E["Exception type<br/>java.lang.ArithmeticException"] --> M["Message<br/>/ by zero"] M --> T1["at Main.main(Main.java:5)<br/>crash is HERE"] T1 --> T2["at Launcher.main(Launcher.java:15)<br/>called from here"] style E fill:#c2410c,color:#fff style T1 fill:#fed7aa style T2 fill:#e2e8f0
Reading a stack trace
A typical stack trace looks like this:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at Main.main(Main.java:5)
Read it from the top down:
- Exception type —
ArithmeticExceptiontells you the category of failure. - Message —
/ by zeroexplains exactly what happened. - Location —
Main.java:5is the file and line number where the exception originated.
In larger programs the trace contains many at lines. The top one is the direct cause; the ones below show which methods called it. Start at the top, fix that line, and re-run. If the top line is in library code you did not write, move down until you reach a file that is yours — that is where you passed the bad value in.
public class Main {
public static void main(String[] args) {
String name = null;
System.out.println(name.length());
}
}
Why the compiler cannot catch everything
The compiler sees the shape of your program — types, method signatures, braces — but it does not know the values that will flow through it at runtime. It knows b is an int, but it has no idea whether b will be 5 or 0 when the division happens. It knows name is a String, but it cannot predict whether some earlier code will set it to null.
This is the fundamental trade-off of static typing: you catch whole categories of errors early, but you still need testing and careful reasoning to catch value-dependent failures. A program that compiles is grammatically correct; only execution proves it is logically correct. Every professional codebase contains compiler-caught errors during development and runtime surprises in production.
flowchart LR
subgraph COMP["Compiler checks"]
C1["Syntax"]
C2["Types match"]
C3["Methods exist"]
end
subgraph RUN["JVM checks at runtime"]
R1["Values != null"]
R2["Divisor != 0"]
R3["Index in bounds"]
end
COMP -->|"builds .class"| RUN
style COMP fill:#c2410c,color:#fff
style RUN fill:#c2410c,color:#fff
What does this program print? Read it carefully and type the exact output (two lines).
public class Main {
public static void main(String[] args) {
int x = 7;
int y = 3;
int diff = x - y;
System.out.println("Difference: " + diff);
System.out.println("Triple: " + (diff * 3));
}
}
x - yis7 - 3 = 4.diff * 3is4 * 3 = 12.This program has no compile or runtime errors.
Which of the following would produce a compile-time error?
int x = "hello"; fails at compile time because the compiler enforces type safety. The other three are valid Java that compiles but crashes at runtime.
What does this program print? Read it carefully and type the exact output (two lines).
public class Main {
public static void main(String[] args) {
int items = 4;
double price = 2.50;
double total = items * price;
System.out.println("Total: " + total);
}
}
items * priceis4 * 2.50.The result is a
double, so it prints with a decimal point.This is a straightforward calculation with no errors.
This program compiles but crashes at runtime. Read it carefully and type the exact output, including the exception message.
public class Main {
public static void main(String[] args) {
int a = 10;
int b = 0;
int result = a / b;
System.out.println("Result: " + result);
}
}
Division by zero is not a compile error — both variables are valid
ints.At runtime the JVM sees
bis0and throws anArithmeticException.Type the exception line and the
atline exactly as they appear.
You see this stack trace:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at Calculator.divide(Calculator.java:12)
at App.main(App.java:8)
Where should you look first to fix the bug?
The top 'at' line under the exception is the exact method, file, and line where the exception was thrown. That is always your first stop. Only if that line is in library code you don't control do you move down to your own code.
Recap
- Compile-time errors are caught by
javac. They mean you broke a language rule. The error message points to a line (check the line above too). - Runtime errors are caught by the JVM. The code is valid Java but hits a bad value. The stack trace tells you the exception type, message, and exact line.
- The compiler checks structure and types; it cannot know runtime values like whether a divisor is zero or a reference is null.
- Read a stack trace from the top down. The first
atline is where the crash began.
Next you will learn to shape the output your programs produce, so the information you print is as precise as the errors Java prints for you.