How to avoid throwing exception from finally block

Viewed 120

I don't want toJson to throw an Exception, but the finally block might throw it. Would it be preferable to wrap the bas.close() in a try/catch block or should this be re-written using try-with-resources

public String toJson() {
    String json = null;
    ByteArrayOutputStream bas = null;

    try {
        bas = new ByteArrayOutputStream();
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.writeValue(bas, this);

        json = new String(bas.toByteArray());
    } catch (Exception e) {
        log.trace("Unable to parse JSON", e); 
    } finally {
        if (bas != null) {
            bas.close();
        }   
    }   

    return json;
}   
2 Answers

You should do it using the try-with-resources statement. Given below is an excerpt from the Oracle's tutorial on The try-with-resources Statement which clearly states the benefit of using it:

Prior to Java SE 7, you can use a finally block to ensure that a resource is closed regardless of whether the try statement completes normally or abruptly. The following example uses a finally block instead of a try-with-resources statement:

static String readFirstLineFromFileWithFinallyBlock(String path)
                                                     throws IOException {
    BufferedReader br = new BufferedReader(new FileReader(path));
    try {
        return br.readLine();
    } finally {
        if (br != null) br.close();
    }
}

However, in this example, if the methods readLine and close both throw exceptions, then the method readFirstLineFromFileWithFinallyBlock throws the exception thrown from the finally block; the exception thrown from the try block is suppressed. In contrast, in the example readFirstLineFromFile, if exceptions are thrown from both the try block and the try-with-resources statement, then the method readFirstLineFromFile throws the exception thrown from the try block; the exception thrown from the try-with-resources block is suppressed. In Java SE 7 and later, you can retrieve suppressed exceptions; see the section Suppressed Exceptions for more information.

Using the try-with-resources statement, you can write your method as follows:

public String toJson() throws Exception {
    String json = null;

    try (ByteArrayOutputStream bas = new ByteArrayOutputStream()) {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.writeValue(bas, this);

        json = new String(bas.toByteArray());
    } 
    return json;
}   

I'd proabably go with something along the lines of:

public String toJson() {

    try (var bas = new ByteArrayOutputStream()) {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.writeValue(bas, this);
        return new String(bas.toByteArray());
    }       
    catch (Exception ie) {
        throw new MyCustomJsonConverterException("Failed to render to JSON");
    }
}

i.e. map to a RuntimeException type if you expect failure to serialize to JSON to be exceptional (a programming error). This is an instance method, after all, and all invariants of the class should already be enforced elsewhere. This way, you take the burden of checking for null from the caller.

Related