Home > Net >  Jdk failed to compile my code that throws exception inside Runnable
Jdk failed to compile my code that throws exception inside Runnable

Time:06-27

I'm trying to throw exception from within a Runnable object, like this:

  class ExceptionRunnable implements Runnable {
    @Override
    public void run() throws Exception {
      throw new Exception("ExceptionRunnable");
    }
  }

Compilation error: xxx.ExceptionRunnable.run() doesn't implement java.lang.Runnable.run(). The overriden run() doesn't throw java.lang.InterruptedException.

This is really odd, I'm throwing a new Exception in the run function, but compiler said I didn't throw anything. I'm using jdk1.8 on windows.

How to handle this?

CodePudding user response:

When compiling your code:

class ExceptionRunnable implements Runnable {
    @Override
    public void run() throws Exception {
        throw new Exception("ExceptionRunnable");
    }
}

The compiler shows the following error:

java: run() in ExceptionRunnable cannot implement run() in java.lang.Runnable
  overridden method does not throw java.lang.Exception

Why? Because the method you're overriding - Runnable.run() - has this signature (note the absence of a throws clause):

void run()

To fix the first issue then, change your code from this:

public void run() throws Exception {

to this, so that the signatures match:

public void run() {

After making that change, you will uncover the next compiler error:

java: unreported exception java.lang.Exception; must be caught or declared to be thrown

This is saying that your own code is throwing an Exception which is both not caught and not declared in the throws clause. You've already found that you can't add it to the throws clause though – that's what you initially tried to do. So the other option would be to catch the exception in your run() method, like below:

@Override
public void run() {
    try {
        throw new Exception("ExceptionRunnable");
    } catch (Exception e) {
        e.printStackTrace();
    }
}

Another option would be to throw a RuntimeException, like below, but you should only do this with intention, fully understanding what it means to introduce unchecked exceptions into your code.

@Override
public void run() {
    throw new RuntimeException("ExceptionRunnable");
}

CodePudding user response:

Looks like a similar question has been asked before: Java : How to override a method and throw exception?

Would throwing a RuntimeException meet your requirement?

  class ExceptionRunnable implements Runnable {
    @Override
    public void run() {
      throw new RuntimeException("ExceptionRunnable");
    }
  }

CodePudding user response:

According to the rules of method overriding can not declare to throw checked exceptions (or their super types up to Throwable) that not declared by parent while overriding the method in the subclass.

A quote from the Language specification:

If m2 has a throws clause that mentions any checked exception types, then m1 must have a throws clause, or a compile-time error occurs.

Such situation when child has less safe behavior that its parent also voilates the Liskov substitution principle, which states that client code that expects an instance of the parent should be able to use its child without knowing it. Because in case when child has less safe behavior, the client would not be to handle it with the code that is suitable for the parent.

Super type Exception is checked (i.e. compiler should ensure that it's handled properly whenever might occur) and method run() doesn't declare to throw any checked exception, therefore you can't override run() by including Exception in the throws close.

You can include any type of unchecked exception in the throws close of run(). The code below is valid and would compile:

class MyRunnable implements Runnable {
    @Override
    public void run() throws RuntimeException {
        // todo
    }
}

All checked exceptions that your code might throw should be handled inside run() and can not be propagated to the caller:

class MyRunnable implements Runnable {
    @Override
    public void run() throws RuntimeException {
        try {
            Thread.sleep(1_000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Note: avoid declare to throw as well as avoid catching super types like Exception, or Throwable, it's a bad habit. Be as much specific as it's possible

  • Related