mxcl
mxcl

Reputation: 26883

How to avoid duplicating complicated catch blocks

I have this code:

try {
    do_stuff();
    return do_more_stuff();
} catch (UnsupportedEncodingException e) {
    throw CustomException.programmer_error(e);
} catch (ProtocolException e) {
    throw CustomException.programmer_error(e);
} catch (MalformedURLException e) {
    throw CustomException.programmer_error(e);
} catch (SocketTimeoutException e) {
    throw new CustomException(e);
} catch (IOException e) {
    throw CustomException.unexpected_error(e);
}

I now need to have all those catch blocks in another similar function. What is the best way to avoid duplication here?

Note that the code inside the two try blocks is not very similar.

Also I can't really put the set of catches higher up.

Note, I'd prefer to avoid:

try {
    do_stuff();
    return do_more_stuff();
} catch (Exception e) {
    handle_exception_via_rtti(e);
}

Upvotes: 19

Views: 3418

Answers (5)

python dude
python dude

Reputation: 8358

How about introducing a generic Action class that can be subclassed:

public class Action {
    public void runWithHandlers() throws Exception {
        try {
           run();
        } catch (UnsupportedEncodingException e) {
            throw CustomException.programmer_error(e);
        } catch (ProtocolException e) {
            throw CustomException.programmer_error(e);
        } catch (MalformedURLException e) {
            throw CustomException.programmer_error(e);
        } catch (SocketTimeoutException e) {
            throw new CustomException(e);
        } catch (IOException e) {
            throw CustomException.unexpected_error(e);
        }
    }
    public void run() throws Exception {
        // TODO subclasses of Action must implement this
    }
}

Then somewhere else in your code you instantiate one of the subclasses of Action and call runWithHandlers():

new MyAction().runWithHandlers();

Upvotes: 1

thSoft
thSoft

Reputation: 22660

If you can afford Scala, check it out: you can pattern match the exception in the catch block. See Scala for Java Refugees Part 4: Pattern Matching and Exceptions.

Upvotes: 0

BalusC
BalusC

Reputation: 1108782

Note, I'd prefer to avoid:

Then either just live with it, or wait until JDK7 comes with Multicatch so that you can rewrite like:

try {
    do_stuff();
    return do_more_stuff();
} catch (UnsupportedEncodingException | ProtocolException | MalformedURLException e) {
    throw CustomException.programmer_error(e);
} catch (SocketTimeoutException e) {
    throw new CustomException(e);
} catch (IOException e) {
    throw CustomException.unexpected_error(e);
}

You can alternatively also move this into the constructor of CustomException and do a (nasty) global catch, but then you'll need to add a bunch of (nasty) if/else blocks to determine the type of the exception cause. All with all, I'd just prefer to stick with the way as you already did.

Update: another alternative is to split/refactor the lines which can potentially throw the exception as separate tasks into another method blocks throwing CustomException. E.g.

try {
    do_stuff_with_encoding();
    do_stuff_with_url();
    do_stuff_with_ws();
    // ...
    return do_more_stuff();
} catch (SocketTimeoutException e) {
    throw new CustomException(e);
} catch (IOException e) {
    throw CustomException.unexpected_error(e);
}

...

public SomeObject do_stuff_with_encoding() throws CustomException {
    try {
        do_stuff();
    } catch (UnsupportedEncodingException e) {
        throw CustomException.programmer_error(e);
    }
}  

public SomeObject do_stuff_with_url() throws CustomException {
    try {
        do_stuff();
    } catch (MalformedURLException e) {
        throw CustomException.programmer_error(e);
    }
}  

public SomeObject do_stuff_with_ws() throws CustomException {
    try {
        do_stuff();
    } catch (ProtocolException e) {
        throw CustomException.programmer_error(e);
    }
}  

Upvotes: 5

user159088
user159088

Reputation:

It depends of why the do_stuff and do_more_stuff throw the checked exceptions. Are they doing that to force the user to treat the exception? If yes, then you trying to avoid:

try {
    do_stuff();
    return do_more_stuff();
} catch (Exception e) {
    handle_exception_via_rtti(e);
}

is a good thing.

If your code just catches Exception, and the do_stuff and do_more_stuff later add extra exceptions, you'll probably never know about the change and the fact that your code could now be wrong.

So you might have to deal with throwing the kitchen sink and treat all those exceptions, unless the methods could switch to unchecked exceptions.

On the other hand, if the methods are throwing checked exceptions just because the programmer was lazy in treating with them and just wanted to pass the buck, maybe you are looking at this from the wrong angle.

Upvotes: 2

p.marino
p.marino

Reputation: 6252

Personally I'd try to make the

do_stuff();
return do_more_stuff();

part conform to a more general format in order to apply Strategy (as a pattern).

Then you can refactor all the places where you call this kind of block so that they can call a more generalized block (where the catches are laid out just once).

Upvotes: 8

Related Questions