torek, 6. september 2011

Resolving Java Exception Hell

Resolving Java Exception Hell

Consider following java exception hell:

public class Utils {
public void processFile(String filename) throws IOException {
        try {
            FileOutputStream fos = new FileOutputStream(filename);
//do something with file
        }
        catch (IOException ex) {
  //make some logging  and exception handling
throw new IOException(ex.getMessage());
        }
    }
}
public class FileProcesser {
public void processSomeFile(String filename) throws IOException {
        try {
Utils u = new Utils();
u.processFile("myFile.txt");
        }
        catch (IOException ex) {
  //catch the exception thrown from utils class
//log here also??
throw new IOException(ex.getMessage());
        }
    }
}

public class Program {
public static void main(String[] args) {
try {
FileProcesser p = new FileProcesser();
p.processSomeFile(args[0]);
}
catch (IOException ex) {
//catch the exception thrown from utils class
//log here also??
throw new IOException(ex.getMessage());
}
}
}



Here we have 3 classes, namely Utils, Fileprocessor, Program. One uses another. Obvisously, the smallest working unit, which does the actual work, can of course fall into exception (which is very normal). But see how the code becomes polluted by that exception. You're passing it to the top calling class. And you can fall into endless artistical design debates on where to the the logging etc. Now image ourself changing exception type or adding addition exception. If you have 10 usages of Utils class in 2 level approach (as in this sample), you will end up with extensive refactorings. 


Now is there any way to get out of this hell? It is... And the solution has name:  RuntimeException. The beauty of runtime exception is, that you need NOT to declare it with throws. Thus, you handle exception where it happens, and write a code in a most logical way.


public class Utils {
public void processFile(String filename) {
        try {
            FileOutputStream fos = new FileOutputStream(filename);
//do something with file
        }
        catch (Throwable ex) {
  //make some logging  and exception handling
throw new RuntimeException(e);
        }
    }
}
public class FileProcesser {
public void processSomeFile(String filename) {
Utils u = new Utils();
u.processFile("myFile.txt");
    }
}
public class Program {
public static void main(String[] args) {
FileProcesser p = new FileProcesser();
p.processSomeFile(args[0]);
}
}

Of course there are hidden implications of this design. Most important point is, that unlike the previous example, the code of this program will stop running. In web application for example, the rendering of the page will stop, and you will most likely redirect to error page. So this solution is best suitable for the cases where you want to stop the execution of a program, if something goes wrong. Which in my case is the best approach. Exceptions are basically of these kinds:

  • formal validation exception (like date not entered). This is actually warning to user
  • fatal exception (you cannot proceede, and you DON'T WANT to proceede)
  • really unexpected exception (you also want your app to crash)
I believe, that it is more important to notice that something went wrong, then trying to hide that. If programs eats the exception, and makes you think everything is cool, this is more a politician way. 

Additional upgrade to solution would be to introduce your own custom excpetion type  (Do not have more than one custom exception in application or it will result in - hell!):

public class FatalException extends RuntimeException {
String desc = "";
public FatalException(String desc, Throwable reason) {
super(reason);
this.desc = desc;
}
private void logEx() {
//super.reason.printStackTrace
}
}

usage: throw new FatalException (e);

With this custom exception, you have one place only in your app, where you handle the exception, do the logging, process exception text, notify user or whatever you need. This will significantly improve your consistency and reduce the amount of code.

You can even query the exception type here:

//Throwable reason; 

if (reason instanceof JAXBException) {
//log
}
else if(reason instanceof IOException) {
//send mail
}
else if(reason instanceof LoginException) {
//log to database
}
else{
//redirect
}

I hope this will help you on your stair way to programming heavens.




6 komentarjev:

  1. I'm here representing the visitors and readers of your own website say many thanks for many remarkable
    python Training institute in Pune
    python Training institute in Chennai
    python Training institute in Bangalore

    OdgovoriIzbriši
  2. Nice tutorial. Thanks for sharing the valuable information. it’s really helpful. Who want to learn this blog most helpful. Keep sharing on updated tutorials…
    Best Devops online Training
    Online DevOps Certification Course - Gangboard
    Best Devops Training institute in Chennai

    OdgovoriIzbriši
  3. This is ansuperior writing service point that doesn't always sink in within the context of the classroom. In the first superior writing service paragraph you either hook the reader's interest or lose it. Of course your teacher, who's getting paid to teach you how to write an good essay, 

    Data Science training in rajaji nagar
    Data Science with Python training in chennai
    Data Science training in electronic city
    Data Science training in USA
    Data science training in bangalore

    OdgovoriIzbriši