They differ if
- the
try-block completes by throwing a java.lang.Throwable that is not a java.lang.Exception, for instance because it is a java.lang.Error such as AssertionError or OutOfMemoryError.
- the try-block completes abruptly using a control flow statement such a
continue, break or return
- the catch-block completes abruptly (by throwing any throwable, or using a control flow statement)
More generally, the java language guarantees that a finally block is executed before the try-statement completes. (Note that if the try-statement does not complete, there is no guarantee about the finally. A statement might not complete for a variety of reasons, including hardware shutdown, OS shutdown, VM shutdown (for instance due to System.exit), the thread waiting (Thread.suspend(), synchronized, Object.wait(), Thread.sleep()) or being otherwise busy (endless loops, ,,,).
So, a finally block is a better place for clean-up actions than the end of the method body, but in itself, still can not guarantee cleanup exeuction.