Bob Balaban's Blog

     
    alt

    Bob Balaban

     

    The Interesting Difference Between "Exception" and "RuntimeException" (Java)

    Bob Balaban  February 2 2013 06:43:32 PM
    Greetings Geeks!

    I hope everyone who attended Lotusphere IBMConnect '13 had a good time and has returned home safely. I didn't attend (again, I stopped going after the first 17), but I've been hearing that it was pretty good.

    I learned something new about certain types of exceptions in Java programming the other day. Here's the context:
    • I had an Enum class with a few items in it
    • I had a String that came from outside the program that I wanted to convert into an enum'ed constant
    • This was happening inside an existing function where I didn't want to add to the "throws" declaration (because that would cause ripple effects up into the functions that called the function I was modifying)

    Here's my first draft implementation (this isn't the real code, I created a standalone example for ya):

    import
    java.io.*;

    public
    class ExceptionTest
    {
           public enum someEnum
           {
                   firstitem, seconditem, thirditem
           }
           
           public static void main(String [] args)
           {
                   try { func1(args[0]); }
                   catch (IOException ioe) {}
                   
                   try { func2(args[0]); }
                   catch (IOException ioe) {}
           }
           
           public static void func1(String arg) throws IOException
           {
                   someEnum myEnum = null;
                   
                   System.out.println("In func1");
                   if (arg.equals("firstitem"))
                           myEnum = someEnum.firstitem;
                   else if (arg.equals("seconditem"))
                           myEnum = someEnum.seconditem;
                   else if (arg.equals("thirtitem"))
                           myEnum = someEnum.thirditem;
                   else System.out.println("Invalid input: " + arg);
                   
                   if (myEnum != null)
                           System.out.println("myEnum: " + myEnum.name());
           }
    }

    Not too bad, but rather tedious.  Note that myEnum.name() will take the enum's item value and convert it into a String.

    A colleague pointed out to me that the Java Enum class (all "enums" are compiled into instances of the class Enum) has a valueOf() method. You give it a string, it returns the enum item (e.g., someEnum..firstitem). So, it's effectively the reverse of the name() method.

    I noticed from the javadoc that this function can throw an IllegalArgumentException. It'll do that if the string you give it doesn't match one of the enum items. So I changed my "func1" implementation into what I'll show you here as func2():

           public static void func2(String arg) throws IOException
           {
                   someEnum myEnum = null;
                   
                   System.out.println("In func2");
                   try { myEnum = someEnum.valueOf(arg); }
                   catch (IllegalArgumentException iae) {}
                   
                   if (myEnum == null)
                           System.out.println("Invalid input: " + arg);
                   else System.out.println("myEnum: " + myEnum.name());
                   
           }

    Simpler, right? I thought at this point that I had it nailed. But then that same colleague said, "Hey, you know you don't need the try/catch there". I was sure he was wrong (this stuff happens to me all the time). "No, I do need it, because I don't want to add IllegalArgumentException to the function 'throws' list." I was sure that if I took out the try/catch I'd get a compile error saying I needed it.

    Buuuuuuutt noooooooo, I was wrong. And here's what I hadn't realized until then: There are TWO categories of Exceptions. Many classes that extend (inherit from) java.lang.Exception (like IOException, for example), are required to either be declared in a "throws" clause in the function declaration, or "caught" in a try/catch block. The compiler enforces this.

    However, SOME exception classes (such as IllegalArgumentException) extend not java.lang.Exception, but java.lang.RuntimeException (which itself extends Exception). These are special, you don't need to catch them or declare them explicitly. Here's the slimmed down version of func2():

           public static void func2(String arg) throws IOException
           {
                   someEnum myEnum = null;
                   
                   System.out.println("In func2");
                   myEnum = someEnum.valueOf(arg);
                   
                   if (myEnum == null)
                           System.out.println("Invalid input: " + arg);
                   else System.out.println("myEnum: " + myEnum.name());
                   
           }

    No compile problems. AND, if you later add more items to the enum, you don't have to change any of the other code.

    If you run this with a valid input (such as "firstitem"). If you run it with something other than a string that matches one of the enum items, you get this:

    Exception in thread "main" java.lang.IllegalArgumentException: No enum constant ExceptionTest.someEnum.item
           at java.lang.Enum.valueOf(Unknown Source)
           at ExceptionTest$someEnum.valueOf(ExceptionTest.java:1)
           at ExceptionTest.func2(ExceptionTest.java:42)
           at ExceptionTest.main(ExceptionTest.java:15)

    Of course, you still CAN use try/catch here. You might do that if you want to catch the "illegal" argument and re-throw an application-specific Exception, or create a nicer error message. But you don't have to, because derivatives of RuntimeException are treated specially by the Java compiler.

    Now you know!

    Geek ya later!

    Follow me on Twitter @LooseleafLLC
    This article ┬ęCopyright 2013 by Looseleaf Software LLC, all rights reserved. You may link to this page, but may not copy without prior approval.

    Comments

    1Koen de Leijer  2/3/2013 1:24:59 PM  The Interesting Difference Between Exception and RuntimeException (Java)

    Hija Bob

    Thanks for your tip/article !

    IBM Connect has been great (I've been to the 19th en 20th edition so far)

    Still love to meet you sometime over there,

    I really appreciate your Lotus/Java-work !

    Regards

    Koen

    PS. You have been mentioned once again during `Ask the developers` about the LSX-Toolkit :-)

    2Bob Balaban  2/3/2013 3:44:16 PM  The Interesting Difference Between Exception and RuntimeException (Java)

    @Koen - thanks for the comments! Sorry to hear about the Developers session comment. They should really move on from the LSX Toolkit to something more important, like fixing DXL or (even better) Designer.

    3Mike Woolsey  3/28/2013 12:37:12 PM  The Interesting Difference Between Exception and RuntimeException (Java)

    Just for my enlightenment ... is there a difference between the functionality of the two snippets? I was thinking that a "catch{}" would continue on and you'd get a "system.out.println()" from the code that follows the "catch{}".

    Kind of a question of, "do I want to stop the whole ball game, or just nicely tell the caller they gave me garbajjje?"

    I know it's a detail, I'm just trying to figger out exactly how all this stuff fits together.

    4Bob Balaban  4/3/2013 5:42:23 PM  The Interesting Difference Between Exception and RuntimeException (Java)

    @Mike - Whether you catch it or not is entirely up to you. If you want to "handle" it (translate it to a different error message, provide more context, whatever), then you would. My point was that a runtime exception can happen whether you catch it, or not, and whether you declare it in the function signature or not