throw vs throws in Java with Examples

Introduction So far we have caught exceptions thrown by the Java library. Your own code can throw exceptions too - to reject an invalid argument, or to report that an operation failed. Java has two keywords for this which look almost the same but do completely different jobs: throw and throws. This tutorial explains throw vs throws in Java with examples. We will start with the throw statement, and use it to validate arguments. We will then declare exceptions with the throws clause, and see how a declared exception travels up to its callers. Next we will rethrow and wrap exceptions while keeping the original cause. Lastly, we will compare the two keywords side by side, and look at the rules for throws when methods are overridden.

(Note - This tutorial builds on Checked vs Unchecked ExceptionsClick to read tutorial: Checked vs Unchecked Exceptions in Java and try, catch, finally and multi-catchClick to read tutorial: Java try, catch, finally and Multi-catch with Examples.) throw - throwing an exception throw is a statement which throws one exception object, right now.
throw new ExceptionType("message");
Where,
  • the expression after throw must be an object of Throwable or a subclass - almost always a newly created exception.
  • the method stops immediately, like a return, and the exception travels up the call stack until a catch block handles it.
  • the message should explain what went wrong, including the bad value, so that whoever reads it can fix the problem.
The most common use is validating arguments at the start of a method, and throwing an IllegalArgumentException - or a more specific exception - when they are invalid. Failing early with a clear message is much better than carrying on with bad data and failing confusingly later.
Validating arguments with throw
//ThrowDemo.java
public class ThrowDemo {
  static double withdraw(double balance, double amount) {
    if (amount <= 0) {
      throw new IllegalArgumentException("Amount must be positive, but was " + amount);
    }
    if (amount > balance) {
      throw new IllegalStateException("Insufficient funds: balance " + balance + ", requested " + amount);
    }
    return balance - amount;
  }

  public static void main(String[] args) {
    System.out.println("New balance: " + withdraw(500, 120));
    double[] requests = {-20, 800};
    for (double amount : requests) {
      try {
        withdraw(500, amount);
      } catch (IllegalArgumentException | IllegalStateException e) {
        System.out.println(e.getClass().getSimpleName() + ": " + e.getMessage());
      }
    }
    String name = null;
    String checked = java.util.Objects.requireNonNull(name, "name must not be null");
  }
}
 OUTPUT of the above code
New balance: 380.0
IllegalArgumentException: Amount must be positive, but was -20.0
IllegalStateException: Insufficient funds: balance 500.0, requested 800.0
Exception in thread "main" java.lang.NullPointerException: name must not be null
	at java.base/java.util.Objects.requireNonNull(Objects.java:246)
	at ThrowDemo.main(ThrowDemo.java:24)
Explanation of the code
  • Each throw stopped withdraw() at once, so no balance was returned for the invalid requests.
  • IllegalArgumentException means "you passed a bad value", and IllegalStateException means "this cannot be done right now". Both are unchecked, so withdraw() does not need to declare them.
  • Objects.requireNonNull() is a ready-made check which throws a NullPointerException with your message when its argument is null. It was not caught, so the program ended with a stack trace.
throws - declaring exceptions throws is part of a method declaration. It lists the checked exceptions the method may throw but does not handle itself, so that its callers know to deal with them.
returnType methodName(parameters) throws ExceptionType1, ExceptionType2 { ... }
Where,
  • several exception types can be listed, separated by commas.
  • for checked exceptions, throws is how a method satisfies the compiler's catch or declare rule. Every caller must then catch or declare them in turn.
  • unchecked exceptions can be listed too, as documentation, but the compiler ignores them.
Declaring checked exceptions with throws
//ThrowsDemo.java
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

public class ThrowsDemo {
  static String readFirstLine(Path file) throws IOException {
    if (!Files.exists(file)) {
      throw new IOException("No such file: " + file);
    }
    return Files.readAllLines(file).get(0);
  }

  static int readPort(Path configFile) throws IOException {     // passes the exception on
    String line = readFirstLine(configFile);
    return Integer.parseInt(line.substring(line.indexOf('=') + 1).trim());
  }

  public static void main(String[] args) throws IOException {
    Path config = Path.of("server.conf");
    Files.writeString(config, "port = 8080\n");
    System.out.println("Port: " + readPort(config));

    try {
      readPort(Path.of("missing.conf"));
    } catch (IOException e) {
      System.out.println("Could not read port: " + e.getMessage());
    }
    Files.delete(config);
  }
}
 OUTPUT of the above code
Port: 8080
Could not read port: No such file: missing.conf
Explanation of the code
  • readFirstLine() both throws an IOException with throw, and declares it with throws - the two keywords working together.
  • readPort() does not handle the exception, so it declares it as well, passing it up to its caller. This is called propagating the exception.
  • main() catches it for the missing file. main() also declares throws IOException, because writeString() and delete() can throw it - acceptable in a small program, but in real applications exceptions should be handled before they reach main().
Rethrowing and wrapping exceptions A catch block can throw too. Two patterns are common -
  • Rethrowing: do something with the exception - such as logging it - then throw e; to pass it on unchanged.
  • Wrapping: throw a new, more meaningful exception, passing the original as its cause. The cause keeps the original details and stack trace, which are shown as "Caused by:" in the output. Never throw a new exception without the cause - the information about what really went wrong would be lost.
Wrapping a low-level exception with its cause
//WrapDemo.java
public class WrapDemo {
  static int parseQuantity(String text) {
    try {
      return Integer.parseInt(text);
    } catch (NumberFormatException e) {
      throw new IllegalArgumentException("Invalid order quantity '" + text + "'", e);   // e is the cause
    }
  }

  public static void main(String[] args) {
    try {
      parseQuantity("12x");
    } catch (IllegalArgumentException e) {
      System.out.println("Message : " + e.getMessage());
      System.out.println("Cause   : " + e.getCause());
    }
    parseQuantity("abc");
  }
}
 OUTPUT of the above code
Message : Invalid order quantity '12x'
Cause   : java.lang.NumberFormatException: For input string: "12x"
Exception in thread "main" java.lang.IllegalArgumentException: Invalid order quantity 'abc'
	at WrapDemo.parseQuantity(WrapDemo.java:7)
	at WrapDemo.main(WrapDemo.java:18)
Caused by: java.lang.NumberFormatException: For input string: "abc"
	at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
	at java.base/java.lang.Integer.parseInt(Integer.java:564)
	at java.base/java.lang.Integer.parseInt(Integer.java:661)
	at WrapDemo.parseQuantity(WrapDemo.java:5)
	... 1 more
The caller sees an exception which describes the problem in its own terms - an invalid order quantity - while the original NumberFormatException is still there, in the "Caused by:" section of the stack trace and through getCause().
throw vs throws - comparison
throwthrows
What it isA statementA clause in a method (or constructor) declaration
What it doesThrows one exception object nowDeclares exception types the method may throw
Followed byAn exception object: throw new IOException("...")One or more class names: throws IOException, SQLException
WhereInside a method bodyAfter the parameter list
Effect on the compilerA thrown checked exception must be caught or declaredSatisfies catch-or-declare; makes callers handle the exceptions

A memory aid: throw is an action, done once; throws is a warning label on the method. throws and method overriding When a subclass overrides a method, its throws clause may only narrow the checked exceptions of the method it overrides: it can declare the same checked exceptions, subclasses of them, or none at all - but not new or broader checked exceptions. Code written against the parent class only expects the parent's exceptions, so a subclass must not surprise it with others. Unchecked exceptions are not restricted.
An overriding method cannot add a broader checked exception
//OverrideThrows.java
import java.io.FileNotFoundException;
import java.io.IOException;

public class OverrideThrows {
  static class Loader {
    void load() throws FileNotFoundException { }
  }

  static class NetworkLoader extends Loader {
    @Override
    void load() throws IOException { }       // IOException is broader than FileNotFoundException
  }
}
 OUTPUT on compiling the above code
OverrideThrows.java:12: error: load() in NetworkLoader cannot override load() in Loader
    void load() throws IOException { }       // IOException is broader than FileNotFoundException
         ^
  overridden method does not throw IOException
1 error
Declaring throws FileNotFoundException, or nothing, in NetworkLoader would compile. Overriding itself is covered in the @Override annotation tutorialClick to read tutorial on the @Override annotation. Summary In this tutorial we first used the throw statement to throw exceptions, and validated method arguments with IllegalArgumentException, IllegalStateException and Objects.requireNonNull(). We then declared checked exceptions with the throws clause, and propagated an IOException up through two methods. Next we rethrew and wrapped exceptions, keeping the original as the cause. We then compared throw and throws side by side, and lastly saw that an overriding method cannot declare broader checked exceptions. In the next tutorial, we will define our own exception classes with custom exceptionsClick to read tutorial: Creating Custom Exceptions in Java with Examples.