What does the throws keyword do?
throws - a keyword in the method signature that documents the contract: it tells the calling code which checked exceptions the method can throw and which the calling code must b...
Junior Level
Definition
throws - a keyword in the method signature that documents the contract: it tells the calling code which checked exceptions the method can throw and which the calling code must be prepared to handle.
public void readFile() throws IOException {
Files.readAllLines(Paths.get("file.txt"));
}
What it means
The method tells the caller: “I may not succeed, and you must know about it”.
The calling code must:
- Wrap the call in
try-catch - Or also add
throwsto its signature
// Option 1: try-catch
public void safeRead() {
try {
readFile();
} catch (IOException e) {
log.error("Failed", e);
}
}
// Option 2: propagate further
public void process() throws IOException {
readFile();
}
Multiple exceptions
public void process() throws IOException, SQLException {
// Can throw both
}
Why throws is needed for checked but not for unchecked
Checked exceptions (inherit Exception, but not RuntimeException) - compiler requires handling. throws is a way for the method to delegate responsibility to the caller: “I don’t know how to handle this error, let the caller decide”.
Unchecked exceptions (inherit RuntimeException) - compiler does not require handling. They represent programming errors (NullPointerException, IllegalArgumentException) that cannot be meaningfully handled - they need to be fixed, not caught. That’s why throws is not needed for them.
// Checked: compiler forces declaration or catch
public void readFile() throws IOException { ... }
// Unchecked: compiler doesn't require throws
public void process(String s) {
if (s == null) throw new NullPointerException();
}
Unchecked exceptions and throws
For RuntimeException, throws is technically not needed, although the language allows writing it:
// No need to write throws NullPointerException
public void process(String s) {
if (s == null) throw new NullPointerException();
}
Although void method() throws RuntimeException compiles, it’s considered bad style - unchecked exceptions should not clutter the signature.
When NOT to use throws
- In public library APIs -
throws Exceptionforces the client to catch “everything” - In interfaces with multiple checked exceptions - sign of SRP violation, split the interface
- In Spring REST controllers - use
@ControllerAdviceinstead ofthrowsin each method - In lambda expressions - functional interfaces don’t support checked exceptions
- For programming errors -
IllegalArgumentException,NullPointerExceptionare not declared viathrows
Middle Level
Bytecode: Exceptions attribute
In the .class file, information about throws is stored in the method’s Exceptions attribute. JVM doesn’t use it for runtime control - only for compiler verifier.
When called through Reflection, JVM won’t force catching exceptions:
Method m = MyClass.class.getMethod("readFile");
m.invoke(obj); // IOException doesn't have to be caught
Binary Compatibility
Adding a checked exception breaks binary compatibility:
// Was:
public void process() { }
// Became - all clients stop compiling
public void process() throws IOException { }
Removing exception - binary compatible (old try-catch will continue working).
Senior Tip: if you need to add validation to a public API, use RuntimeException or create an overloaded method.
Overriding and LSP
Liskov Substitution Principle:
interface Service {
void process() throws IOException;
}
class Impl implements Service {
@Override
// CAN: not throw at all (narrowing contract)
public void process() { }
@Override
// CAN: throw a subtype
public void process() throws FileNotFoundException { }
// CANNOT: new checked exception - compilation error
// public void process() throws IOException, SQLException { }
}
Unchecked and throws
Technically you can write void method() throws RuntimeException, but it’s bad style. Unchecked exceptions should not clutter the signature. For documentation, use @throws in JavaDoc.
Senior Level
Throws as documentation
Consider throws as part of the contract. throws InsufficientFundsException says more about business logic than any comment.
Generic Throws
Java allows generics:
public <E extends Exception> void doWork(ThrowingRunnable<E> task) throws E {
task.run();
}
Actively used in functional interfaces and wrappers.
Interface Segregation
If an interface throws too many different throws - sign of SRP violation. Method does too many things.
// Bad - too many responsibilities
public interface Service {
void process() throws IOException, SQLException, AuthException, ValidationException;
}
// Good - split into interfaces
public interface DataService {
void save() throws DataAccessException;
}
public interface AuthService {
void authenticate() throws AuthException;
}
// Even better - in Spring use @ControllerAdvice
@RestController
public class OrderController {
// throws not needed - @ControllerAdvice will catch
@PostMapping("/orders")
public Order createOrder(@RequestBody OrderRequest req) {
return orderService.create(req);
}
}
ReflectiveOperationException
On Reflection, all checked exceptions of the called method are wrapped in InvocationTargetException.
throws Exception - undesirable pattern
In most cases, don’t write throws Exception in public API. It forces the client to catch “everything”, depriving the ability to adequately react to specific failures.
Diagnostics
javap -v MyClass.class- you’ll see theExceptionsattribute in bytecode- Binary compatibility check - tools like JAPICC check version compatibility
- Static Analysis - Sonar blocks
throws Exceptionin public APIs
Interview Cheat Sheet
Must know:
throwsdocuments the method contract - which checked exceptions the caller must handle- Checked exceptions (not
RuntimeException) compiler requires to declare or catch - Unchecked exceptions (
RuntimeException) don’t requirethrows- these are programming errors - On overriding you can narrow
throws(remove or replace with subtype), but not expand - Adding a checked exception breaks binary compatibility - clients will stop compiling
- In Spring REST use
@ControllerAdviceinstead ofthrowsin each method throws Exceptionin public API - anti-pattern, forces client to catch “everything”
Frequent follow-up questions:
- Must checked exceptions be caught? - Yes, either
try-catchor your ownthrows - Can you add
throws RuntimeException? - Technically yes, but bad style - What happens on method override? - Can remove
throwsor narrow, but not expand (LSP) - How is
throwsstored in bytecode? -Exceptionsattribute in.class, JVM doesn’t check at runtime
Red flags (NOT to say):
- “I write
throws Exceptioneverywhere for simplicity” - anti-pattern, client can’t handle adequately - “I don’t declare checked exceptions - compiler won’t notice” - won’t compile
- “
throwsaffects runtime performance” - no, it’s only a compiler check - “Can add new checked exception without consequences” - breaks binary compatibility
Related topics:
- [[21. Can you throw a checked exception from a method without throws]] - bypass via sneaky throws
- [[2. What is a checked exception and when to use it]] - nature of checked exceptions
- [[3. What is an unchecked exception (Runtime Exception)]] - why they don’t require
throws - [[27. Can you rethrow an exception]] - rethrow preserving
throws - [[13. Can you create custom exceptions]] - custom exceptions for
throws