Rakesh KR
Rakesh KR

Reputation: 6527

chained exception facility in JAVA

I can acheive chained Exception facility in java as

case 1:

public static void main(String[] args) {

    try {
        method1();
    } catch (Exception e) {
        System.out.println("Exception in the main method :: "+e);
    }

}

private static void method1() throws Exception {
    try{
        System.out.println("Inside Try Block"+10/0);
    } catch(ArithmeticException e){
        System.out.println("Exception in method1 :: "+e);
        throw e;
    } finally{
        System.out.println("In FinallY Block");
    }

}

case 2 :

public static void main(String[] args) {

    try {
        method1();
    } catch (Exception e) {
        System.out.println("Exception in the main method :: "+e);
    }

}

private static void method1() throws Exception {
    try{
        System.out.println("Inside Try Block"+10/0);
    } catch(ArithmeticException e){
        System.out.println("Exception in method1 :: "+e);
        throw (ArithmeticException)new ArithmeticException().initCause(e);
    } finally{
        System.out.println("In FinallY Block");
    }
}

And I got the output as

Exception in method1 :: java.lang.ArithmeticException: / by zero
In FinallY Block
Exception in the main method :: java.lang.ArithmeticException: / by zero

And My Question is :

  1. Is there any difference between these two cases ?
  2. Which is the better method ?
  3. And why 2 cases for the same purpose ?

Upvotes: 1

Views: 172

Answers (2)

Nathan Hughes
Nathan Hughes

Reputation: 96454

You should pass the cause in as a constructor argument, instead of calling initCause.

In real code you don't see an exception thrown wrapping the same type of exception. The point is to wrap an implementation-level exception in something higher-level, so that the code catching the exception doesn't have a lot of implementation-specific special cases to handle (and implementation details don't bleed through to parts of the code that shouldn't have to care), while the chaining makes sure the original stacktrace is retained.

So you'd do something like:

private static void method1() throws HigherLevelException {
    try{
        System.out.println("Inside Try Block"+10/0);
    } catch(ArithmeticException e){
        throw new HigherLevelException(e);
    }
}

Since a lot of people consider checked exceptions to be a failed experiment (not even dot-net chose to copy them), in a lot of cases the higher level exception tends to be an unchecked exception. You'll see this pattern with Spring and Hibernate.

In your first example catching an exception just to rethrow it should not be necessary. The stacktrace should be sufficient to determine where the exception was generated without having to log and rethrow. Make sure you have one centralized place that catches and logs exceptions.

Upvotes: 1

Joffrey
Joffrey

Reputation: 37859

  1. The difference is you wrap the original ArithmeticException exception in another exception of same type in the second case (see below why this is pointless).

  2. Case 1 is probably what you want to use here, because you don't broaden the meaning of your exception (to a higher level).

  3. They don't have the same purpose, let me explain...

If you set an exception as a cause, it doesn't have the same meaning. You can give a larger meaning to the ArithmeticException by wrapping it in a higher-level exception. Here you're just wrapping it in another ArithmeticException, which does not make sense.

A case where you might want a cause is for instance when you try to get some data from a web service: the low-level methods sending HTTP requests throw some SocketException or HttpException, and you wrap them in some higher-level exceptions describing what resource couldn't be loaded (for instance).

Upvotes: 1

Related Questions