Java throws Keyword
Table of Contents + −
In the last lesson you learned about the Java throw keyword, which raises an exception. Now meet its close cousin with one extra letter: throws. It does not raise anything. It declares in a method’s signature that the method might throw a certain exception, so callers get warned ahead of time.
🤔 Two families: checked and unchecked
Java splits every exception into two groups. The group decides whether throws is required. This is the most important idea in this lesson.
A checked exception is one Java checks for at compile time. The compiler sees a line that could fail and makes you prove you have a plan, or the code will not compile:
- They usually come from the outside world: a missing file, a dropped network connection, a database that is down.
- The classic example is
IOException, which input and output operations can throw. - You must either catch it or declare it with
throws. There is no third option.
An unchecked exception is a runtime problem Java does not force you to handle. The compiler stays quiet:
- They usually come from bugs in your own logic.
- Examples are
NullPointerException,ArithmeticException, andArrayIndexOutOfBoundsException. - You can catch them, but Java never forces you to, and you never need
throwsfor them.
Why the split? A missing file is not your fault. It can happen even when your code is perfect, so Java wants a plan. A NullPointerException is a mistake in your code. The fix is to correct the bug, not wrap every line in error handling. So only checked exceptions force you to use throws.
🧩 What does throws do?
The throws keyword goes at the end of a method’s signature, after the parentheses. It declares that the method might throw one or more exceptions. It is a promise to callers: “if you call me, be ready, this kind of problem can come out of me.”
Here is the general shape:
// the throws clause sits after the parameter list, before the method bodyreturnType methodName() throws ExceptionType { // code that might throw ExceptionType}This line does not throw anything. It only announces the possibility. So when a method declares throws IOException, the caller has a choice:
- Catch the
IOExceptionwith a try-catch block, or - Declare
throws IOExceptionon their own method too, and pass the warning further up.
This is the handle-or-declare rule. For every checked exception, you either handle it (catch it) or declare it (with throws). You cannot stay silent. That is how the responsibility travels from one method to the next.
💡 A method that declares throws
Reading a file is a perfect case. The file might not exist. The disk might be full. So IOException is checked, and a method that reads a file must catch it or declare it. Here we declare it and let the caller deal with it.
import java.io.IOException;import java.io.FileReader;
public class Main {
// ❌ this method does NOT handle the error itself; it declares it static void readFile() throws IOException { FileReader reader = new FileReader("data.txt"); reader.read(); reader.close(); }
public static void main(String[] args) { try { readFile(); // ✅ caller handles the declared exception } catch (IOException e) { System.out.println("Could not read file: " + e.getMessage()); } }}Let’s read this:
readFileopens a file and reads from it. Both can fail with anIOException.- Instead of catching it,
readFiledeclaresthrows IOException. It says “I might throw this; you deal with it.” maincallsreadFile, somainis the caller who got warned. It must handle the exception.mainwraps the call in a try-catch. So if the file is missing, the program prints a friendly message instead of crashing.
The key point: without that throws on readFile, this code would not even compile. IOException is checked, and you gave it no plan.
Output
Could not read file: data.txt (The system cannot find the file specified)⛓️ Propagating an exception up
A method does not have to handle an exception itself. It can declare throws and let the exception travel up to whoever called it. This travelling is called propagation. Each method in the chain makes the same choice: handle it here, or pass it on.
Here is a chain of three methods so you can watch the exception move.
static void methodC() throws IOException { // raise the exception right here throw new IOException("Something failed deep down");}
static void methodB() throws IOException { methodC(); // does NOT catch; just declares throws and passes it up}
static void methodA() { try { methodB(); // ✅ finally handled here } catch (IOException e) { System.out.println("Handled in methodA: " + e.getMessage()); }}Follow the path of the exception:
methodCraises theIOExceptionwiththrow.methodBdoes not catch it. It only declaresthrows IOException, so the exception passes straight through.methodAfinally catches it in a try-catch.
Why is this useful? The deepest method often does not know what to do about the error. methodC just reads bytes. But methodA, higher up, knows the bigger picture. So letting the exception rise to the right level keeps each method simple. You handle the error where the decision makes sense, not where it started.
What if nobody catches it? It keeps rising until it leaves main, then Java prints a stack trace and the program stops. So main is the last stop. Catch it before there, or the program ends.
🧮 Declaring more than one exception
A method might throw several checked exceptions. You do not need a separate clause for each. Just list them after throws, separated by commas.
import java.io.IOException;import java.text.ParseException;
// declares TWO checked exceptions, separated by a commastatic void loadAndParse() throws IOException, ParseException { // reading a file can throw IOException // parsing its contents can throw ParseException}The caller now knows about both risks. It can catch them in one block if it treats them the same, or in separate catch blocks for different handling. Either way, the throws clause kept the caller honest about every checked problem this method can produce.
⚖️ throw vs throws, side by side
These two are the most confused pair in Java exceptions. They look almost identical:
- throw (no s) raises an exception, right now, inside the method body. It is followed by an exception object, like
throw new IOException("..."). throws(with s) declares, in the method signature, that the method might throw one. It is followed by exception types, likevoid read() throws IOException.
In one sentence: throws warns that an exception may come, throw actually makes one happen. A single method often uses both together.
// throws (with s) DECLARES the risk in the signaturestatic void withdraw(int amount) throws IllegalAccessException { if (amount > 1000) { // throw (no s) RAISES the exception right now throw new IllegalAccessException("Limit exceeded"); }}The signature announces the possibility with throws. Then one line in the body creates it with throw. The declaration is the warning label. The throw is the actual break.
Unchecked exceptions do not need throws
You never have to declare throws for unchecked exceptions like NullPointerException or IllegalArgumentException. Java does not force it. You only need throws (or a catch) for checked exceptions like IOException.
⚖️ When to declare vs when to catch locally
You must handle-or-declare, but which one? Here is a simple way to choose:
- Catch it locally when you know how to recover. If you can retry, use a default value, or show a clear message, deal with it right there.
- Declare it with
throwswhen this method cannot make a good decision. If only a higher caller knows what to do, pass it up.
So a low-level helper that just reads bytes usually declares. A high-level method, closer to the user, usually catches, because it can show a message or pick a fallback. Match the handling to the place with enough context.
⚠️ Common Mistakes
A few throws slip-ups to watch for.
Mixing up throw and throws. They are not interchangeable. throw raises an object; throws declares a type. Swapping them is a syntax error.
// ❌ wrong: throws expects a type, not an objectthrows new IOException("oops");
// ✅ right: throw raises the objectthrow new IOException("oops");Ignoring a checked exception. You cannot stay silent about a checked exception. You must catch it or declare it, or the code will not compile.
// ❌ wrong: IOException is checked but neither caught nor declaredstatic void readFile() { new FileReader("data.txt"); // compile error}
// ✅ right: declare it so the caller is warnedstatic void readFile() throws IOException { new FileReader("data.txt");}Declaring throws for unchecked exceptions needlessly. It is allowed, but it adds noise and tells callers nothing useful. Reserve throws for checked exceptions where it is actually required.
// ❌ pointless: NullPointerException is uncheckedstatic void greet(String name) throws NullPointerException { }
// ✅ clean: no throws needed for unchecked exceptionsstatic void greet(String name) { }Swallowing an exception and then re-declaring it. Do not catch an exception, do nothing useful with it, and still declare throws for it. Pick one honest path. Either truly handle it, or let it propagate. Catching it just to hide it loses the error and confuses everyone.
✅ Best Practices
Habits for using throws well.
- Handle exceptions at the right level. If a method cannot sensibly deal with an error, declare
throwsand let a higher caller handle it. - Catch checked exceptions only where you can recover. Use try-catch when you genuinely know what to do about the problem.
- Keep your
throwslists honest. Declare the exceptions a method really can throw, no more and no less, so callers are properly warned. - Prefer specific exception types over a broad
throws Exception. A precise type tells the caller exactly what can go wrong. - Remember the spelling difference.
throwto raise,throwsto declare.
🧩 What You’ve Learned
Nicely done. Let’s recap throws.
- ✅ Java has checked exceptions (you must handle or declare) and unchecked ones (you need not).
- ✅
throwsin a method signature declares that the method might throw a checked exception. - ✅ The handle-or-declare rule: a caller must catch the exception or declare it too.
- ✅ Exceptions propagate up the call chain until a method handles them, or escape
mainand stop the program. - ✅ You can declare several exceptions after
throws, separated by commas. - ✅
throwraises an exception;throwsdeclares one — same idea, different jobs.
Check Your Knowledge
Test what you learned. Pick an answer for each question, then click Check.
- 1
What does the throws keyword do?
Why: throws declares the possibility of an exception; it does not raise one itself.
- 2
What is special about a checked exception?
Why: Checked exceptions like IOException must be handled or declared, or the code will not compile.
- 3
If method B calls a method that throws a checked exception but does not catch it, what must B do?
Why: B must either catch the exception or declare throws to pass it up the call chain.
- 4
What is the difference between throw and throws?
Why: throw actually raises an exception; throws declares that a method may throw one.
🚀 What’s Next?
Java’s built-in exceptions cover many cases, but sometimes your program has its own kinds of errors, like “InsufficientFundsException” in a bank app. You can create your own exception types. Let’s finish the module by learning custom exceptions.