(How) is it possible to catch an exception in a Java ternary operator statement?

Viewed 1236

I'm reformatting some legacy code that I don't fully understand, and in it there are several variable assignments that conditionally assign variables to the output of one of two formatting functions, using exception catching like so:

String myString;
try {
    myString= foo(x);
} catch (Exception e) {
    myString= bar(x);
}

This seems like an abuse of exception handling, and anyway it's a lot of repeated boilerplate code for a lot of variable assignments. Without digging into foo to identify the conditions that might cause exceptions, can I simplify this using a ternary operator expression? I.e. something like this:

String myString = foo(x) ? foo(x) : bar(x)

but catching the exception that might be thrown by foo(x). Is there a way to do this in this one-liner? Or if not, is there a better one-line expression that chooses between two assignments based on a possible exception? I am using Java 8.

3 Answers

One could use lazy evaluation as follows:

String myString = attempt(() -> foo(x), () -> bar(x));

public static <T> T attempt(Supplier<T> a, Supplier<T> b) {
    try {
        return a.get();
    } catch (Exception e) {
        return b.get();
    } 
}

It is not nice and just would be one stage in the entire refactoring.

One pattern for such constructs you saw would be a result message of a process that maybe throws an IOException.

An ugly pattern would be a NullPointerException or such, when data is optional. Then a complexer redesign with Optional.ofNullable and .map to another Optional might be feasible.

In short I do not see a clean way.

Washcloth answer is already clear. Just wanna add a bit though about your statement:

it's a lot of repeated boilerplate code for a lot of variable assignments.

If you don't want to assign a variable repeatedly, you can create a new method to return String value as below:

String myString = assign(x);

String assign(String x) {
    try {
        return foo(x);
    } catch (Exception e) {
        return bar(x);
    }
}

You only need to assign the variable once with the above method.

Considering this case

String myString;
try {
    myString= foo(x);
} catch (Exception e) {
    myString= bar(x);
}

What would happen if foo(x) throws an exception because it can't handle strings with UTF-16 characters, then we would use bar(x) instead.

In your ternary operator case String myString = foo(x) ? foo(x) : bar(x) if you check foo(x) first and it throws an error your entire program would error out which leads us back to putting a try statement around your ternary operator.

Without the original code its hard to say why the developers did it this way but above is an outlined case as to why they chose this design practice. Also good to note that not all legacy code is bad, in this case; the legacy code works, is maintainable, and easy to read for new developers. So as the comment says, best to leave it this way.

Edit

You said you wanted some sort of 1 liner that reduces boiler plate. You could do something like this

void hee(String mystring) {
    try {
        myString= foo(x);
     } catch (Exception e) {
        myString= bar(x);
     }
}

Putting this function in a utility class followed by changing myString = foo(x) to hee(x) would suffice since your original object X is not a primitive java type. This solution is backwards compatible (since this is legacy code I'm unsure what jdk you are using) and requires minimal explanation.

Related