Kiah Starck
Kiah Starck

Reputation: 47

Is "precise rethrow with a final exception" working in Java SE 8?

public class TestException extends except2 {

    public static void main(String[] args)throws Exception  {
       try {
            try {
                throw new TestException();
            }
            catch (final TestException e){         
            }
            throw new except2();
        }
        catch (TestException a){
        }
        catch (Exception e){
            throw e;
        }
    }

    public TestException(){
    }
}

class except2 extends Exception{
}

Hi all,

my JDK version is 8u45 which is latest one now.

I'm wondering that is "precise rethrow with a final exception" still working in SE 8?

As the code, if I take the "throws Exception" off it'll be compilation error, but it should be able to be ignored according to "precise rethrow with a final exception" function of SE7.

Another question is that we all know if there's an exception happened in the nested try box, we should still throw it out to outer catch box to avoid compilation error, I originally figured that we only need to throw an exception of any types & it'll do, so is my test result, I think it's to let compiler know that there's an exception in try box & catch box got it, too.

but if I alter it like the following code:

public class TestException extends except2 {
    public static void main(String[] args)throws Exception  {
       try {
            try {
                throw new ArithmeticException();
            } catch (final TestException e){
                throw e;
            } 
        } catch (TestException a){
        } catch (Exception e){
            throw e;
        }
    }
}

the (final TestException e) part will be compilation error with the message:

"the Exception "com.xxx.TestException" is never thrown in the corresponding try block",

and I'm confused because if nested catch block can't handle the exception, it shall goes to outer.

Then if I throw an ArithmeticException in the end of outer try block like this:

try {
    try {
        throw new TestException();
    }
    catch (final TestException e){
        System.out.println("d");
    }

    throw new ArithmeticException();
}
catch (TestException a){
}
catch (Exception e){
    throw e;
}

Same error to the outer catch box catch (TestException a){}

Why is that?

it should be caught by (Exception e) block.

If I can't throw different types of exception from the first exception of nested try block, why could I throw except2 in the first paragraph of code?

Upvotes: 0

Views: 209

Answers (2)

eckes
eckes

Reputation: 10433

This is Oracles example for the feature, and it still works with Java 8:

static class FirstException extends Exception { }
static class SecondException extends Exception { }

public void rethrowException(String exceptionName)
   throws FirstExceptio, SecondException // Since J7 no "Exception" needed
{
  try {
    if (exceptionName.equals("First")) {
      throw new FirstException();
    } else {
      throw new SecondException();
    }
  } catch (Exception e) {
    throw e; // effective final (i.e. not assigned)
  }
}

This is described in the second half of this Oracle document. Your examples are all not really related to it. Especially not the one where you have a more specific and a general catch. This is explicitly mentioned in the document as not working.

Your first block would work if you use except2 (I renamed it to BaseException) which is the more specific one like this:

public class TestException extends BaseException {

    public static void main(String[] args) {
       try {
            try {
                throw new TestException();
            }
            catch (final BaseException e){
              throw e; // this is defined as BaseEx, will fail on Java 6
            }
        }
        catch (TestException a){ // this knows that no BaseEx is expected
        }
    }

    public TestException(){
    }
}

class BaseException extends Exception { }

As you can see, the main() method does not need to throw Exception anymore since the second catch block was sufficient.

Upvotes: 2

Sotirios Delimanolis
Sotirios Delimanolis

Reputation: 280138

Your first piece of code can be shortened to

class TestException extends except2 throws Exception {
    public static void main(String[] args) {
        try {
            throw new except2(); // this
        } catch (TestException a) {
        } catch (Exception e) {
            throw e;
        }
    }

    public TestException() {
    }
}

class except2 extends Exception {
}

You're throwing an except2. A TestException is an except2, but an except2 is not necessarily a TestException. The first catch block cannot handle the except2 exception. So the second one must. Since it further throws that exception, and that exception is necessarily checked, you need to have a throws clause.

Your second piece of code

class TestException extends except2 {
    public static void main(String[] args) throws Exception {
        try {
            try {
                throw new ArithmeticException();
            } catch (final TestException e) { // nothing above throws a TestException
                throw e;
            }
        } catch (TestException a) {
        }
        catch (Exception e) {

            throw e;
        }
    }
}

Is trying to catch a TestException in the nested try block. But since TestException is a checked exception, the compiler can and does check if it can be thrown in that block. In your case, it can't. So it complains that's it useless to try and catch it.

Finally, in your last snippet

class TestException extends except2 {
    public static void main(String[] args) throws Exception {
        try {
            try {
                throw new TestException();
            } catch (final TestException e) {
                System.out.println("d");
            }
            throw new ArithmeticException();
        } catch (TestException a) {
        } catch (Exception e) {
            throw e;
        }
    }
}

You're throwing and catching a TestException in the nested try-catch statement. So you can reduce the code to

class TestException extends except2 {
    public static void main(String[] args) throws Exception {
        try {
            throw new ArithmeticException();
        } catch (TestException a) {
        } catch (Exception e) {
            throw e;
        }
    }
}

Which has the same issue as your second piece of code. There is no code path there that can throw a TestException.


Regarding comments, and to simplify the second snippet, the error reduces to

class TestException extends except2 {
    public static void main(String[] args) throws Exception {
        try {
            throw new ArithmeticException();
        } catch (final TestException e) { // nothing above throws a TestException
            throw e;
        }
    }
}

You have a catch(TestException) but nothing throws a TestException, so it's useless code which the compiler rejects.


From comments, this is the problem with your cases 2 and 3

// ignore everything around this
try {
    // nothing in this block 
    // can throw a TestException

    throw new ArithmeticException();

// this whole catch block is useless code
// Test Exception can never be thrown
} catch (final TestException e){ 
    throw e;
} 
// ignore everything around this

Upvotes: 1

Related Questions