5

I understand these are necessary...of course to write proper code, but is there a design pattern that will help avoid having to repeat try...catch blocks repeatedly in a class? For instance, I wrote a particular class that throws 5 different exceptions.

public void iterateComparatorResults(ArrayList<ComparatorValue> results) throws IOException, IllegalArgumentException, IntrospectionException, IllegalAccessException, InvocationTargetException {
    Iterator<ComparatorValue> iterator = results.iterator();
    for(int i=0; i<results.size(); i++) {
        //Set data variables.
        setBeans(results.get(i).getClientBean(), results.get(i).getServerBean());
        setValues(results.get(i).getClientValue(), results.get(i).getServerValue());

        if(results.get(i).isMatch()) {
            //Data matches.
            runIteratorTrueAction();
        } else if(results.get(i).getInnerBeans() != null){
            //Value is a nested bean. Iterate again.
            ArrayList<ArrayList<ComparatorValue>> innerResults = results.get(i).getInnerBeans();
            for(int r=0; r<innerResults.size(); r++) {
                iterateComparatorResults(innerResults.get(r));
            }

        } else {
            //Data does not match.
            runIteratorFalseAction();
        }
    }
}

Everytime I reference this particular method is any other class, I have to use a try catch block that looks like this.

try {
    beanComparator.setIteratorFalseAction(falseAction);
                beanComparator.iterateComparatorResults(beanComparator.compareBeans(contact, compareContact));
} catch (IllegalArgumentException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} catch (IntrospectionException e) {
    e.printStackTrace();
} catch (IllegalAccessException e) {
    e.printStackTrace();
} catch (InvocationTargetException e) {
    e.printStackTrace();
}

I am hoping there is some design pattern I can implement so I can create a separate class or something and hide all the try blocks in one place then reference that class and use the try blocks without actually having to write them. Similar to the way that other frameworks like Spring do? I just need a little direction on how to do this as I have no idea even where to begin.

ryandlf
  • 27,155
  • 37
  • 106
  • 162
  • Can't you put these lines in a method..? And instead of repeating them, call that method with specific arguments (i.e. method name to invoke, parameters to pass to that method, etc.). – Mudassir Feb 06 '12 at 03:36
  • You shouldn't need to catch IllegalArgumentException unless you expect it to happen frequently, since it's a `RuntimeException`. – Louis Wasserman Feb 06 '12 at 03:54

6 Answers6

8

I'm not sure how real-world your example is, but there's no need to a) catch each exception separately, if you don't handle them differently, or b) catch them at all, in many cases.

What you're doing in your example, just printing a stack trace, is a bad idea in almost all cases. You're printing messy information to a place where no one's likely paying attention.

I follow two general guidelines:

  1. Handle the exception at the point at which it's thrown, if you can (to close an open file on a file access exception, for instance, or retry a troublesome interface (stupid unreliable bespoke USB devices...)).
  2. Allow the exception to bubble up to a point higher in your stack, where you can catch all exceptions you can't otherwise handle. Log them, display them, or kill your application, whatever makes the most sense.

I'll illustrate the second point with some code, stolen from inspired by the Java tutorials.

private String readFirstLineFromFile(String path) throws IOException
{
    try (BufferedReader br = new BufferedReader(new FileReader(path)))
    {
        return br.readLine();
    }
}

Here, we've defined a method that attempts to read from a file. Lots of things can go wrong here, but there's nothing the code at this level is going to do about that. Instead, it's going to pass the buck to the method that called it, with the throws clause. That calling method may handle the exception itself, or pass the buck to its caller, with the same clause:

private String readAllTheFiles() throws IOException
{
    for (...)
    {
        readFirstLineFromFile(...);
    }
}

Now, there's lots of debate around why Java requires the throws in this case. Many other languages don't use them, for better or worse. You'll often see RuntimeExceptions - exceptions that don't require a throws clause. If your method might throw an exception that extends from RuntimeException, you don't need to declare that fact in a throws.

Michael Petrotta
  • 59,888
  • 27
  • 145
  • 179
  • +1. This really is the only way to go. If you do not actively recover from an exception when you catch it, do not bother catching it at all. – Maxpm Feb 06 '12 at 03:37
  • Apparently I need a little schooling on this issue. I get what you're saying. Honestly, when my IDE tells me I need to catch an exception, I do. Could I get a bit more detailed response just to give me some direction on how to implement a proper error catching system, or possibly a link to a resource? Like, where should I be storing the data, and what type of data should I pass? I don't quite understand the second guideline? – ryandlf Feb 06 '12 at 03:40
  • @ryandlf, your IDE isn't saying you need to catch the exception, it's saying you need to either catch the exception *or declare that your method throws that exception*. I'll update my answer. – Michael Petrotta Feb 06 '12 at 03:43
  • I also added some additional code to give a better example of another situation where the code just looks messy due to exceptions. – ryandlf Feb 06 '12 at 03:45
  • @ryandlf, I've extended my answer to (hopefully) address your comments and concerns. – Michael Petrotta Feb 06 '12 at 03:59
5

If you are using JDK-7 you can wrap catch block like this

catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
} 
RanRag
  • 48,359
  • 38
  • 114
  • 167
2

All Exceptions extend the class Exception (some how down the line), so what you can do is:

try {
    sql = (SQL) MethodUtils.invokeExactMethod(bean, "getSQL", (Object[])null);
} catch (Exception e) {
    e.printStackTrace();
} 

You could also add a throws statement to methods so that whoever calls your class methods can add the try catch in their code.

void myMethod() throws NoSuchMethodException, IllegalAccessException,
                       InvocationTargetException {
    //  Do stuff that can throw an exception.
}
scaryrawr
  • 777
  • 4
  • 12
  • I'd never admit I do this, but using "main() throws Exception {" solves the problem pretty quick. Every time... yep ;0 – J-Dizzle Sep 19 '16 at 19:11
0

You can catch them and rethrow them as a RuntimeException, like so...

 try {
     sql = (SQL) MethodUtils.invokeExactMethod(bean, "getSQL", (Object[])null);
 } catch(Exception e){
     throw new RuntimeException(e);
 }
nathan
  • 4,612
  • 6
  • 32
  • 33
  • and are you going to write another try {} catch() {} to catch RuntimeException??? – Fahim Parkar Feb 06 '12 at 03:34
  • Not necessary trying to create a new class. Just mentioned that as an example of how I might be able to do it. I probably should have been more specific. – ryandlf Feb 06 '12 at 03:36
  • @FahimParkar I just assumed he was trying to escape the Java "checked exceptions" feature. Other languages don't require you to catch all your exceptions. Rethrowing checked exceptions as runtime exceptions emulates that. – nathan Feb 06 '12 at 03:37
0

If you're using Java 7, you can use multiple exception catching. It'd simplify the code to this:

try {
    sql = (SQL) MethodUtils.invokeExactMethod(bean, "getSQL", (Object[])null);
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
    e.printStackTrace();
}

This is better than just catching Exception, as you still only catch the exceptions that you want.

Also, you probably don't actually want to catch exceptions like that and not handle them aside from logging them. You are better off either performing some error handling, or throwing them out to the calling method for it to handle.

Michael
  • 6,141
  • 2
  • 20
  • 21
0

I think you should create a custom exception, and when exception is caught it's a good idea to throw exception to upper layer, so that it can be handled properly in UI,

try {
    sql = (SQL) MethodUtils.invokeExactMethod(bean, "getSQL", (Object[])null);
} catch (Exception e) {
    throw new InvocationFaliureException(e);
}

here InvocationFaliureException is a custom exception,

public InvocationFaliureException extends Exception
{
....
}
Low Flying Pelican
  • 5,974
  • 1
  • 32
  • 43
  • This seems a little better. How would I handle specific exceptions differently by catching them all in one custom exception? For instance, referencing the code in my question I have 5 different exceptions. How could I write the custom class to handle the first differently than the 5th and also know the difference? – ryandlf Feb 06 '12 at 03:48