Vladislav Ashikhin
Vladislav Ashikhin

Reputation: 308

How to stop java method execution after throwing exception inside of 'inner' method?

I wrote an example which depicts my issue. I have a simple exception:

public class TryToSpeakException extends RuntimeException {

    public TryToSpeakException(String message) {
        super(message);
    }
}

Then I have a chain of methods that invoke each other one by one:

public class TryToSpeak {

    public static void speakToPerson1() {
        throw new TryToSpeakException("Person 1 don't wanna speak to anyone.");
    }

    public static void speakToPerson2() {
        try {
            speakToPerson1();
        } catch (Exception e) {
            System.out.println("speakToPerson2 caused exception");
            e.printStackTrace();
        }
    }

    public static void speakToPerson3() {
        try {
            speakToPerson2();

        } catch (Exception e) {
            System.out.println("speakToPerson3 caused exception");
            e.printStackTrace();
        }
    }

    static void keepSilentToPerson() {
        System.out.println("Keeping silent to person 1");
    }

    public static void communicate() {
        try {
            speakToPerson3();

            keepSilentToPerson(); // Why it reaches this part?
        } catch (Exception e) {
            System.out.println("Communication exception.");
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        communicate();
    }
}

The method from the very 'bottom' throws an exception. In method communicate() after invocation of method speakToPerson3() the execution keeps going. What i need - is to Stop execution, so that invocation of method keepSilentToPerson() is never reached and gives me the message "Communication exception.".

This is what i get in console now:

speakToPerson2 caused exception
exceptions.TryToSpeakException: Person 1 don't wanna speak to anyone.
    at exceptions.TryToSpeak.speakToPerson1(TryToSpeak.java:7)
    at exceptions.TryToSpeak.speakToPerson2(TryToSpeak.java:12)
    at exceptions.TryToSpeak.speakToPerson3(TryToSpeak.java:22)
    at exceptions.TryToSpeak.communicate(TryToSpeak.java:36)
    at exceptions.TryToSpeak.main(TryToSpeak.java:46)
Keeping silent to person 1

But if i call speakToPerson2() from my Main method like this:

public static void speakToPerson1() {
    throw new TryToSpeakException("Person 1 don't wanna speak to anyone.");
}

public static void speakToPerson2() {
    try {
        speakToPerson1();

        keepSilentToPerson();
    } catch (Exception e) {
        System.out.println("speakToPerson2 caused exception");
        e.printStackTrace();
    }
}

static void keepSilentToPerson() {
    System.out.println("Keeping silent to person 1");
}

public static void main(String[] args) {
    speakToPerson2();
}

I get an obvious result:

    speakToPerson2 caused exception
    exceptions.TryToSpeakException: Person 1 don't wanna speak to anyone.
    at exceptions.TryToSpeak.speakToPerson1(TryToSpeak.java:7)
    at exceptions.TryToSpeak.speakToPerson2(TryToSpeak.java:12)
    at exceptions.TryToSpeak.main(TryToSpeak.java:26)

keepSilentToPerson() is not reached.

What am i doing wrong?

Upvotes: 3

Views: 8194

Answers (4)

wilmol
wilmol

Reputation: 1920

speakToPerson2() is catching the Exception, but you want communicate() to catch it too. Essentially, speakToPerson2() is suppressing the exception, so no other method sees it.

What you need to do is rethrow it (in both speakToPerson2() and speakToPerson3()). This is known as propagating an exception.

I.e.:

public static void speakToPerson2() {
    try {
      speakToPerson1();
    } catch (Exception e) {
      System.out.println("speakToPerson2 caused exception");
      e.printStackTrace();
      throw e;
    }
  }

  public static void speakToPerson3() {
    try {
      speakToPerson2();

    } catch (Exception e) {
      System.out.println("speakToPerson3 caused exception");
      e.printStackTrace();
      throw e;
    }
  }

Upvotes: 2

YouKnowWhoIAm
YouKnowWhoIAm

Reputation: 344

You need to propagate your Exceptions to the main class to completely stop the execution of a program.

In the case 1: All your exception will be handled by speakToPerson2 function.

In the case 2: Your exception occurs at the function call of speakToPerson1, so the rest of your code will not execute.

So, inorder to stop the program from running you just have to propagate the exception, using throw keyword, in the catch block of your exception.

Upvotes: 0

D. Lawrence
D. Lawrence

Reputation: 949

You need to understand exactly how try-catch work. If any method in the try-catch throws an exception (one that extends/or is Exception in your example), the body of the try-catch will be interrupted to go into the catch clause.

In your case, the method speakToPerson1 will throw a TryToSpeakException. This exception will be forwarded one step above in the method call stack, the method speakToPerson2 in your case. Since the call to speakToPerson1 is surrounded with a try-catch, the catch clause is invoked and System.out.println("speakToPerson2 caused exception"); is executed. Now, the try clause encloses two methods calls, namely speakToPerson1 and keepSilentToPerson. However, since the first method throw the exception, the second is never reached and therefore keepSilentToPerson() will never by called.

Finally, think about the catching of exceptions. If you catch an exception, you are saying that you are going to handle it, by recovering or rethrowing it. If you handle it without rethrowing it, it won't be forwarded to the upper level of your call stack. Beware of this technicality

Upvotes: 2

Smile
Smile

Reputation: 4088

You can throw the exception after catching it speakTo* methods. This will stop execution of code in methods calling speakTo* and their catch block will be executed.

       catch (Exception e) {
            System.out.println("speakToPerson2 caused exception");
            e.printStackTrace();
            throw e;
        }

Upvotes: 0

Related Questions