Among throw and throws, the throws keyword is considered riskier, while throw is more straightforward.
throw keyword
The below picture shows how exception object is thrown by programmer to JVM
throw keywordSometimes we can create Exception object explicitly and we can handover to the JVM manually for this we have to use throw keyword.
throw new ArithmeticException("/ by zero");
throw : Manually passes the created exception object to the JVM.
new ArithmeticException("/ by zero"); : Creates exception object explicitly.
Example:-
In both cases below, the output remains the same:
In the first example, main method is responsible for creating exception object whereas in second example, programmer is responsible for creating an exception object.
These both program have the same output:
Exception in thread "main" java.lang.ArithmeticException: / by zero
at ThrowNThrows.Test.main(Test.java:5)
But,
Why explicitly create exceptions?
Consider a banking system where a user attempts to withdraw more money than is available. The system returns an error like "Insufficient funds in your account." You don't have an exception like InsufficientFundException in JAVA predefined, so you have to create your own. Internally, this is handled using a custom exception:
withdraw(double amount){
if(amount > balance){
throw new InsufficientFundException();
}
}
Just like in the above example, the best use of throw keyword is for user defined exceptions or customized exceptions. We'll discuss about customized exception later in the blog.
throw keyword is mostly used for customized exception.
Edge Cases for throw
CASE 1: Throwing an Exception Object
We can manually create an exception object and throw it. This works fine.
class Test1 {
static ArithmeticException e = new ArithmeticException(); // creating exception object
public static void main(String[] args) {
throw e;
}
}
Output:-
Exception in thread "main" java.lang.ArithmeticException
at ThrowNThrows.Test1.<clinit>(Test1.java:5)
at java.base/java.lang.Class.forName0(Native Method)
Problem: Throwing an Uninitialized Exception
If the exception object is not initialized, throw will result in a NullPointerException.
class Test2 {
static ArithmeticException e; // default object value null
public static void main(String[] args) {
throw e; // e refers null
}
}
Output:-
Exception in thread "main" java.lang.NullPointerException: Cannot throw exception because "ThrowNThrows.Test2.e" is null
at ThrowNThrows.Test2.main(Test2.java:8)
CASE 2: Unreachable Code After throw
If an exception occurs at runtime, the next statement will not execute.
class Test {
public static void main(String[] args) {
System.out.println(10 / 0);
System.out.println("Hello"); // will not be executed
}
}
Output:-
Exception in thread "main" java.lang.ArithmeticException: / by zero
at ThrowNThrows.CASE2.Test.main(Test.java:5)
Problem: Compiler Error for Unreachable Code
When using throw, the compiler detects unreachable code, leading to a compile-time error.
class Test {
public static void main(String[] args) {
throw new ArithmeticException("/ by zero");
System.out.println("Hello"); // Unreachable code
}
}
Note: After a throw statement, no further code can be executed unless handled with conditions like if-else.
CASE 3: Throwing Non-Throwable Objects
Only objects of Throwable type can be thrown. If we attempt to throw a normal Java object, it results in a compilation error.
class Test {
public static void main(String[] args) {
throw new Test(); // Incompatible types
}
}
Output:-
ThrowNThrows/CASE3/Test.java:5: error: incompatible types: Test cannot be converted to Throwable
throw new Test();
^
1 error
error: compilation failed
Solution: Extending Throwable
If the class extends RuntimeException, it can be thrown.
class Test2 extends RuntimeException {
public static void main(String[] args) {
throw new Test2();
}
}
Output:-
Exception in thread "main" ThrowNThrows.CASE3.Test2
at ThrowNThrows.CASE3.Test2.main(Test2.java:5)
throws keyword
The throws keyword is used when a method might throw a checked exception.
Example 1: Checked exception (FileNotFoundException)
import java.io.PrintWriter;
class WritingInFile {
public static void main(String[] args) {
PrintWriter pw = new PrintWriter("abc.txt");
pw.println("Hello");
}
}
Trying to access a file that may not be available will give an exception.
Output:
❯ javac WritingInFile.java
WritingInFile.java:5: error: unreported exception FileNotFoundException; must be caught or declared to be thrown
PrintWriter pw = new PrintWriter("abc.txt");
^
1 error
Example 2:
class Sleep {
public static void main(String[] args) {
Thread.sleep(10000); //sleeps for 10 seconds
}
}
Whenever we call sleep method there may be a chance that main method may sleep, so it'll give an exception.
Output:
ThrowNThrows/Throws/Sleep.java:5: error: unreported exception InterruptedException; must be caught or declared to be thrown
Thread.sleep(10000);
^
1 error
error: compilation failed
Ways to Handle Checked Exceptions
Way 1: Using try-catch(Recommended)
When you want to handle the exception on your own, you use try-catch .
class SleepProgram {
public static void main(String[] args) {
try{
Thread.sleep(10000); //sleeps for 10 seconds
} catch(InterruptedException e){
System.out.println("Exception handled");
}
}
}
Way 2: Using throws (Delegates responsibility to caller)
When you need to pass/delegate the responsibility of handling exception to the caller method, we can use throws keyword.
class SleepProgram{
public static void main(String[] args) throws InterruptedException{
Thread.sleep(10000);
}
}
Here, the JVM handles the exception.
Key points:
- throws keyword is only required for checked exception.
- There is no impact of throws keyword in unchecked exception
- throws keyword is required only to convince compiler
- Uses of throws keyword doesn't prevent abnormal termination of the program.
Example: Exception Delegation
In this example, exceptions are delegated from methods to methods and finally to the JVM so we don't get any compile time error.
class Test {
public static void main(String[] args) throws InterruptedException {
doStuff();
}
public static void doStuff() throws InterruptedException {
doMoreStuff();
}
public static void doMoreStuff() throws InterruptedException {
Thread.sleep(5000);
}
}
Try removing throws InterruptedException from different methods to observe compile-time errors.
Edge Cases for throws
CASE 1: Allowed for Methods & Constructors, Not for Classes
We can use throws keyword for methods and constructor but not for classes.
class Test{
Test() throws Exception {
}
public void m1() throws Exception {
}
}
CASE 2: throws Must Be Used with Throwable Types
class Test{
public void m1() throws Test{ // ❌ Compile-time error
}
}
Solution:
class Test extends RuntimeException{
public void m1() throws Test{ // ✅ Valid
}
}
The above code is valid because class Test is of type throwable . We can use throws keyword only for throwable types. If we try to use it for normal JAVA classes, then we will get compile time error saying incompatible types.
CASE 3: Checked vs. Unchecked Exceptions
Can you tell which will program will compile?
The answer is, First one… will not compile. Because Exception is a checked exception, so if we don't handle it compulsorily the program will not compile. Whereas, Error is unchecked exception so the second one will compile fine but we will get runtime exception.
CASE 4:
Take a look at these codes and try to answer which of these are gonna run. Hint: out of these five, three codes runs perfectly.
Did you guess the answer? The answer is 2, 4 and 5. 1 and 3 will not be able to run.
Inside a try block if there is no chance of rising an exception then we can't write catch block for that exception otherwise we will get compile time error saying, Exception xxx is never thrown in body of corresponding try statement. But this rule is applicable only for fully checked exception.
Top comments (0)