DEV Community

Cover image for Throw & Throws - [OOP & Java #9]
Liu Yongliang
Liu Yongliang

Posted on • Edited on

Throw & Throws - [OOP & Java #9]

Exceptions

Exceptions are things that worth special consideration. This could mean that the execution of some method is "exceptional" because it might result in errors.

We, therefore, handle exceptions in our program to avoid errors.
There are two main branches of exceptions, checked and unchecked exceptions.

Summary

Exception Checked Unchecked
Error Compile-time Run-time
Occurrence Anticipate and handle Unanticipated
Example IOException FileNotFoundException ... NullPointerException ArithmeticException ...
Strategy Must declare or catch Result in bugs to be fixed

Try-catch

One way to deal with known exceptions is to put dangerous code in a try-catch block.

try {
  // Might result in FileNotFoundException
  FileReader file = new FileReader(args[0]);
  // any other code that might result in exceptions
} catch (FileNotFoundException e) {
  // do something about the exception
}
Enter fullscreen mode Exit fullscreen mode

When we catch an exception, we could resolve it by printing out some message to the caller, or we could simply throw the exception at the caller. Actively raising an exception is still considered a way of "handling" exceptions.

try {
  // something dangerous here
} catch (IOException e) {
  // simply throw exceptions
  // can throw different exceptions
  throw new NullPointerException("My exception message here");
}
Enter fullscreen mode Exit fullscreen mode

Throw

The keyword throw is used to raise exceptions. It could be used within a catch block to resolve another exception. It could also be used whenever we would like to raise an exception.

// some method
public void test() {
  throw new ArrayStoreException("Throwing it because I want to");
}
Enter fullscreen mode Exit fullscreen mode

Throws

Instead of using try-catch, we could simply declare in the method signature that this method could throw some exceptions that callers must look out for. Note that we don't declare unchecked/run-time exceptions because they cannot be anticipated.


Let's see some code examples.

  // might throw unchecked exceptions, which is typical
  void willThrowUnchecked() {
    // does some stuff
    throw new NullPointerException("this is an unchecked exception");
  }

  // DON'T DO THIS, unchecked exceptions need not be declared 
  void willThrowUnchecked2() throws NullPointerException {
    throw new NullPointerException("this is an unchecked exception");
  }

  // might throw a checked exception
  void willThrowChecked() throws IOException {
    // pretend that it might throw an exception
    throw new IOException();
  }

  // DON'T DO THIS, checked exceptions must be declared
  // will not compile 
  void willThrowChecked2() {
    throw new IOException();
  }
Enter fullscreen mode Exit fullscreen mode

Unchecked exceptions

  • The function call within this method body does not throw checked exceptions, hence ok to not do any handling.
  // will compile
  void useUnchecked() {
    willThrowUnchecked();
  }
Enter fullscreen mode Exit fullscreen mode
  • Unchecked exceptions need NOT be anticipated. No known checked exceptions anticipated. Hence ok to not do any handling.
  // will compile
  void useUnchecked2() {
    willThrowUnchecked2();
  }
Enter fullscreen mode Exit fullscreen mode
  • We can handle unchecked exceptions, if we want to
  // will compile
  void useUnchecked3() {
    try {
    willThrowUnchecked();
  } catch (NullPointerException e) {
     System.out.println("hello");
  }
}
Enter fullscreen mode Exit fullscreen mode

Checked exceptions

  • If we don't handle checked exceptions, we are not allowed to use potentially dangerous methods.
  // will not compile
  void useChecked() {
    willThrowChecked();
  }
Enter fullscreen mode Exit fullscreen mode
  • We declare that the current method is dangerous, so whenever this method is called, the caller needs to handle it. we passed the responsibility to the caller of this method. This is considered "handling" exceptions as well.
  // will compile
  void useChecked2() throws IOException {
    willThrowChecked();
  }
Enter fullscreen mode Exit fullscreen mode
  • We handled the exception using try-catch, safe and sound.
  // will compile
  void useChecked3() {
    try {
      willThrowChecked();
    } catch (IOException e) {
      System.out.println("I handled it!");
    }
Enter fullscreen mode Exit fullscreen mode
  • We handled it by throwing another exception, still safe.
  // will compile
  void useChecked4() {
    try {
      willThrowChecked();
    } catch (IOException e) {
      throw new NullPointerException("Hey there is a problem!");
    }
  }
Enter fullscreen mode Exit fullscreen mode
  • If we throw a checked exception as a response, we must declare it.
  // will NOT compile
  void useChecked4() {
    try {
      willThrowChecked();
    } catch (IOException e) {
      throw new IOException ("Hey there is a problem!");
    }
  }

  // will compile
  void useChecked4() throws IOException {
    try {
      willThrowChecked();
    } catch (IOException e) {
      throw new IOException ("Hey there is a problem!");
    }
  }
Enter fullscreen mode Exit fullscreen mode

Throws vs Throw

The two keywords are not exactly comparable because they serve different purposes. They can co-exist in a single method. Hence, the usage of the two reserved words depend on the situation.

Summary

Throws Throw
Purpose To declare checked exceptions To throw any exceptions
Usage when the method body contains code that might throw checked exceptions As a way to raise exceptions (both checked and unchecked) to the caller
Example void test() throws IOException {} throw new NullPointerException("WRONG");

Top comments (0)