An exception thrown from the finally block will replace any exception that was thrown from the try, and information about the real problem is likely to be lost.
Since the try-finally block is allowed to throw an IOException in this case, here's a better way to write it:
try (BufferedReader bufferedReader = Files.newBufferedReader(Paths.get("file.txt"))) {
/* Work with `bufferedReader` */
}
This automatically closes the reader when the block exits, and handles any resulting exceptions nicely, even if the code inside the try block throws its own exception first, using the "suppression" mechanism of Throwable.
If the try block completes without exception, the result will be the result of closing the resource (exception or not). If the try block throws an exception, that will be the exceptional result. But if the close() method raises an exception too, it will be added to the try block's exception as a "suppressed" exception. You can interrogate it programmatically, and when the stack trace is printed, the suppressed exception will be displayed, much like the "caused by" exceptions you may be more familiar with.
And, you can try-with-multiple resources; these will all be closed, and multiple closure exceptions can be suppressed.
This assumes you're using file I/O, but the same "try-with-resources" structure will work on anything that implements AutoCloseable (streams, SQL objects, etc.).