7

In java, it is not recommended to throw exceptions inside finally section in try-chatch block due to hide the propagation of any unhandled throwable which was thrown in the try or catch block. This practice is a blocker level violation according to default sonar profile.

Sonar Error: Remove this throw statement from this finally block.

Please consider the following code snippet.

e.g.: close input stream inside the finally block, and handle possible exceptions might be occurred when closing the stream.

    public void upload(File file) {
        ChannelSftp c = (ChannelSftp) channel;
        BufferedInputStream bis = new BufferedInputStream(file.toInputStream());
        try {
            String uploadLocation = Files.simplifyPath(this.fileLocation + "/" + file.getName());
            c.put(bis, uploadLocation);
        } catch (SftpException e) {
            throw new IllegalTargetException("Error occurred while uploading " + e.getMessage());
        } finally {
            try {
                bis.close();
            } catch (IOException e) {
                throw new UnsupportedOperationException("Exception occurred while closing Input stream " + e.getMessage());
            }
        }
    }

It would be grateful if you can show the conventional way of handling these situations.

Hiran Perera
  • 736
  • 1
  • 5
  • 18
  • 7
    as a sidenote, the more smooth solution would be the usage of [try-with-ressources](https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html) – SomeJavaGuy Dec 20 '16 at 14:54
  • Thanks for the advice. – Hiran Perera Dec 20 '16 at 14:57
  • 1
    Think about what happens when the finally-block is being executed after throwing that `IllegalTargetException` and another `UnsupportedOperationException` is thrown. Which of those would the caller get? The same is true with return-statements in finally-blocks, you'd tamper with the control flow which will lead to disaster. – Thomas Dec 20 '16 at 15:00
  • The general problem here is that throwing from `finally{}` hides any exceptions that the main body has thrown. Use try-with-resources for this sort of thing. – BadZen Dec 20 '16 at 15:01
  • Possible duplicate of [How to avoid throw clause in finally block](http://stackoverflow.com/questions/28187304/how-to-avoid-throw-clause-in-finally-block) – Paul Brinkley Dec 20 '16 at 15:05
  • `try-with-ressources` is often relevant but in case when you want to trace the exception that prevents the stream from being closed or you have to perform a recovery processing, it hides the problem. – davidxxx Dec 20 '16 at 15:09
  • According to your advises, try-with-resource is the best solution for this problem. – Hiran Perera Dec 20 '16 at 15:16

1 Answers1

10

Best way to handle this problem is to use try-with-resource. But if someone want to close the connection manually and show the exception of the try or catch block without hiding, following code snippet is the solution.

public void upload(File file) throws IOException {
    ChannelSftp c = (ChannelSftp) channel;
    BufferedInputStream bis = new BufferedInputStream(file.toInputStream());
    SftpException sftpException = null;
    try {
        String uploadLocation = Files.simplifyPath(this.fileLocation + "/" + file.getName());
        c.put(bis, uploadLocation);
    } catch (SftpException e) {
        sftpException = e;
        throw new IllegalTargetException("Error occurred while uploading " + e.getMessage());
    } finally {
        if (sftpException != null) {
            try {
                bis.close();
            } catch (Throwable t) {
                sftpException.addSuppressed(t);
            }
        } else {
            bis.close();
        }
    }
}
Hiran Perera
  • 736
  • 1
  • 5
  • 18