Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exceptions propagate up Call Stack

I'm having a hard time quite understanding the concept, or really the usefulness, of having Exceptions propagate up the call stack. I get how to create them, but I don't really see when they would be used, like in a simple real world application for math or something.

public void method1(){
    try{
        method2();
    }
    catch(Exception e){
        e.printStackTrace();
    }
}

public void method2(){
      try{
          throw new Exception();
      }
      finally{
         System.out.println("no exception, try cleanup");
      }
}

I get that this is basically how it would work, though it would probably be more involved with more exceptions and functions, but I don't really get the point of using these instead of just having catches in every function.

like image 561
sl133 Avatar asked Jan 13 '23 20:01

sl133


2 Answers

... but I don't really get the point of using these instead of just having catches in every function.

The point is that next function up the call stack may not know how to handle the exception. Example:

public class Test {

    public Object doSomething(String source) throws IOException {
        try (InputStream is = openAsStream(source)) {
            // ... read and process stuff
            return ...
        }
    }

    public InputStream openAsStream(String name) throws IOException {
        String fileName = // ... do something with 'name'
        return new FileInputStream(name);
    }

    public static void main(String[] args) {
        // ...
        Test t = new Test();
        try {
            t.doSomething(args[0]);
        } catch (IOException ex) {
            System.err.println("Cannot handle '" + args[0] + "'");
        }
    }
}

The openAsStream calls the FileInputStream constructor which may throw an IOException. The openAsStream method cannot recover from this so it lets it propagate. The doSomething method doesn't know how to deal with it either, so it allows it to propagate. Finally, the exception gets to main ... which knows how to explain the problem to the user.


Now you could write openAsStream to catch the IOException, print an error message and return a null. But that would be a big mistake:

  • The openAsStream() doesn't (and shouldn't) know whether / how to report the problem to the user.

  • And if it returns a null to the caller, then the caller has to test to see whether the result of the call is null ... and take alternative action.

The point is that a method should only handle exceptions that can be adequately dealt with at that level. Others should be allowed to propagate. (Or maybe wrapped in another exception ... if that is what the API design requires.)

like image 120
Stephen C Avatar answered Jan 16 '23 09:01

Stephen C


Exception propagation makes your code fail-fast on errors by default.

Consider the alternative approach to exception propagation - returning an error code. If the caller to your code, accidentally or deliberately, does not test for error codes, then they could use your method, not be aware that your object is now in an unusuable state, and continue calling methods and causing undefined behaviour/memory corruption. If you threw an exception instead, then if the caller forgets to catch exceptions then instead of doing horrible things they fail fast, and the programmer can be alerted as to where it was thrown, why and what to do about it. Exceptions are loud and obnoxious because they indicate conditions that need to be considered.

like image 20
Patashu Avatar answered Jan 16 '23 09:01

Patashu