Jul 24

I’m not the first who’s going to be suggesting a different approach to the problem checked exception causes: Boiler-plate code.

Let’s sum it up: Checked exceptions mean that we need to either catch an exception thrown by a method call, or declare that the method we’re implementing throws that exception, unless the exception is RuntimeException or a subclass of it.

This means that, when calling File.createTempFile, we can either write:


public void myMethod() throws IOException {
  File f = File.createTempFile("pre", "suf");
}

Or:


public void myMethod() {
  try {
    File f = File.createTempFile("pre", "suf");
  } catch (IOException e) {
    // do something with e.
  }
}

When part of a larger application, you won’t just declare the exception because it is considered an ugly design: It reduces abstraction by revealing part of your lower-level, internal implementation. That’s why what’s usually done with exceptions is to either log it, or wrap it in an API specific exception (such as a JAXBException wrapping IOException).

However, that tends to become boiler-plate code. For example, the following code:


Class clz = ...
try {
  a = clz.getConstructor(Integer.TYPE).newInstance(5);
} catch (InstantiationException e) {
  throw new MyException(e);
} catch (IllegalAccessException e) {
  Logger.log(e);
} catch (IllegalArgumentException e) {
  throw new MyException(e);
} catch (InvocationTargetException e) {
  throw new MyException(e);
} catch (NoSuchElementException e) {
  throw new MyException(e);
} catch (SecurityException e) {
  Logger.log(e);
}

I mean… Just look at it! And you see that everywhere. And worse, a lot of people start to rethrow RuntimeException to rid themselves from “the problem”. Checked exceptions aren’t be a problem: they are an extremely helpful tool, aimed to help developers have another layer in their interface and module design. The problem we have is the syntax offered, or rather, the syntax lacking to deal with many exceptions and the aforementioned boiler-plate code.

As I said, lately it’s a fashion to suggest your own syntax as a solution, so I’m adding my two cents, and suggest the following:

  • Adding a throws rethrown exception instance for exception type list : caught exception instance type caught exception instance name clause directly after the try clause and before other catch clauses; this will rethrow the exception for any exception of the types mentioned.
  • Adding a catch caught exception type list : caught exception instance type caught exception instance name clause directly after the previous point’s clause and before the normal catch clause; this will catch all exceptions of the specified types.
  • So, the previous example will be coded to be:

    
    Class clz = ...
    try {
      a = clz.getConstructor(Integer.TYPE).newInstance(5);
    } throws new MyException(e) for InstantiationException,
          NoSuchElementException, InvocationTargetException,
          IllegalArgumentException : Exception e;
      catch (IllegalAccessException, SecurityException : Exception e) {
        Logger.log(e);
    }
    

    The previous code would obviously unfold to the original code – This is “syntax sugar”, but one that is much needed!

    I’d like to hear your opinion, and of other ways this could have been done better – Please comment!

    Related Posts with Thumbnails
    Share

    9 Responses to “Let’s try .. throws .. catch .. finally”

    1. omry Says:

      For one, you got a hole: the name of the exception ‘e’ is never defined, only used.

      second, is solves a very specific case.
      I don’t think its a very useful construct.
      to summarize:
      NOT IN MY JAVA! :)

    2. Avah Says:

      Oops. It is meant to be defined by my suggestion (read the text!)

      It’s for ease-of-development. Too much of this boiler-plate code and we’re lost – and this at least let’s you know what’s going to happen for each exception.

    3. Avah Says:

      P.S. Fixed it.

    4. Reinier Zwitserloot Says:

      Okay, some comments. #2 is overly complex. The following works fine (doesn’t conflict with parser design, doesn’t lead to binary/source incompatibilities, doesn’t make previously valid java code do something different/break in new code):

      try { /* something */ }
      catch ( IOException, NumberFormatException e ) {}

      There is no need to explicitly specify how you’ll be treating e; it’s the common ancestor. In case there are multiple common ancestors (only happends if exceptions start implementing custom interfaces which rarely happends), ignore the interface part of the hierarchy, or, alternatively, turn e into a joint type. Java does support this ‘under the hood’ since java 1.5. (Generics parameters can have joint types, and the tertiary operator can return joint types – the idea that the type of the expression is A && B – it is guaranteed to be both so you can assign it to a variable of either type.

      In regards to the rethrows form, I don’t like it. I don’t think it’s needed either – once this multi-list thing is possible, you can roll your own in 3 lines which is hardly worse than the special syntax. here’s your complete example, rewritten the way I’d implement this stuff:

      Class clz = ...
      try {
      a = clz.getConstructor(Integer.TYPE).newInstance(5);
      } catch ( InstantiationException, NoSuchElementException, InvocationTargetException, IllegalArgumentException e ) {
      throw new MyException(e);
      } catch ( IllegalAccessException, SecurityException e ) {
      Logger.log(e);
      }

      It adheres to all the quality standards for a language change:

      1. it does not conflict with any existing code; there is no code that compiles today that would do something different/no longer compiles with this change adapted.

      2. it does not create binary or source incompatibilities; this is just syntactic sugar that gets compiled the same way as writing each catch block separately.

      3. it is intuitive and simple to understand.

      4. it does not conflict with the current parser strategy.

      5. it solves a useful problem that has been observed in the wild for many years and does not appear to be going away anytime soon.

    5. Avah Says:

      I agree with everything except for the deduction of the exception’s type. It might be true that it can be done, but it’s unreadable if the exception object is actually used, for example, if I have an exception MyException and two subclasses MyException1 and MyException2, and MyException has a method getSomeInformation(), I want to be able to know for a fact that “e” is going to be MyException, so I can know for a fact I can call that method.

    6. Akhilesh Says:


      Class clz = ...
      try {
      a = clz.getConstructor(Integer.TYPE).newInstance(5);
      } catch (InstantiationException e) {
      throw new MyException(e);
      } catch (IllegalAccessException e) {
      Logger.log(e);
      } catch (IllegalArgumentException e) {
      throw new MyException(e);
      } catch (InvocationTargetException e) {
      throw new MyException(e);
      } catch (NoSuchElementException e) {
      throw new MyException(e);
      } catch (SecurityException e) {
      Logger.log(e);
      }

      Can be transformed to:


      Class clz = ...
      try {
      a = clz.getConstructor(Integer.TYPE).newInstance(5);
      } catch (SecurityException e) {
      Logger.log(e);
      }catch (IllegalAccessException e) {
      Logger.log(e);
      } catch (Exception e) {
      throw new MyException(e);
      }

      Assumption: The caught exceptions are the only checked exceptions thrown by the funciton called.

    7. Avah Says:

      But your assumption is exactly the kind of thing I am trying to avoid. And what if a RuntimeException is thrown somehow? (null pointer, array index, etc?)

    8. Ben Says:

      The Java closures proposal (http://javac.info/) has the syntax

      throws Exception1|Exception2

      Could this be used in the catch clause?

      try {
      someMethod();
      } catch (Exception1|Exception2 extends BaseException e) {
      throw new MyException(e)
      }

      It could be a compile time error if any of Exception1, Exception2 don’t extend BaseException.

      The extends clause could be allowed to be omitted (and then treated as being ‘extends Throwable’).

      From my reading of the JLS, the catch clause in the byte code allows specifying multiple exceptions for a single catch block.

    9. faisal Says:

      I need help ..
      I can work from the campus in order to make java program that uses exceptions TRY, Catch and as many as 40 rows TRHOW ..
      Please help you?
      if anyone have the program please send to my email ..
      faisalrusli@yahoo.co.id
      thank you in advance