34

In a Java try{} ... catch{} ... finally{} block, code within the finally{} is generally considered "guaranteed" to run regardless of what occurs in the try/catch. However, I know of at least two circumstances under which it will not execute:

  • If System.exit(0) is called; or,
  • if an Exception is thrown all the way up to the JVM and the default behavior occurs (i.e., printStackTrace() and exit)

Are there any other program behaviors that will prevent the code in a finally{} block from executing? Under what specific conditions will the code execute or not?

EDIT: As NullUserException pointed out, the second case is actually not true. I thought it was because the text in standard error printed after that in standard out, preventing the text from being seen without scrolling up. :) Apologies.

asteri
  • 11,402
  • 13
  • 60
  • 84

9 Answers9

37

If you call System.exit() the program exits immediately without finally being called.

A JVM Crash e.g. Segmentation Fault, will also prevent finally being called. i.e. the JVM stops immediately at this point and produces a crash report.

An infinite loop would also prevent a finally being called.

The finally block is always called when a Throwable is thrown. Even if you call Thread.stop() which triggers a ThreadDeath to be thrown in the target thread. This can be caught (it's an Error) and the finally block will be called.


public static void main(String[] args) {
    testOutOfMemoryError();
    testThreadInterrupted();
    testThreadStop();
    testStackOverflow();
}

private static void testThreadStop() {
    try {
        try {
            final Thread thread = Thread.currentThread();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    thread.stop();
                }
            }).start();
            while(true)
                Thread.sleep(1000);
        } finally {
            System.out.print("finally called after ");
        }
    } catch (Throwable t) {
        System.out.println(t);
    }
}

private static void testThreadInterrupted() {
    try {
        try {
            final Thread thread = Thread.currentThread();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    thread.interrupt();
                }
            }).start();
            while(true)
                Thread.sleep(1000);
        } finally {
            System.out.print("finally called after ");
        }
    } catch (Throwable t) {
        System.out.println(t);
    }
}

private static void testOutOfMemoryError() {
    try {
        try {
            List<byte[]> bytes = new ArrayList<byte[]>();
            while(true)
                bytes.add(new byte[8*1024*1024]);
        } finally {
            System.out.print("finally called after ");
        }
    } catch (Throwable t) {
        System.out.println(t);
    }
}

private static void testStackOverflow() {
    try {
        try {
            testStackOverflow0();
        } finally {
            System.out.print("finally called after ");
        }
    } catch (Throwable t) {
        System.out.println(t);
    }
}

private static void testStackOverflow0() {
    testStackOverflow0();
}

prints

finally called after java.lang.OutOfMemoryError: Java heap space
finally called after java.lang.InterruptedException: sleep interrupted
finally called after java.lang.ThreadDeath
finally called after java.lang.StackOverflowError

Note: in each case the thread kept running, even after SO, OOME, Interrupted and Thread.stop()!

randers
  • 5,031
  • 5
  • 37
  • 64
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • 2
    I'm surprised it ran even after the thread was killed. The [documentation](http://docs.oracle.com/javase/tutorial/essential/exceptions/finally.html) says "if the thread executing the try or catch code is interrupted or killed, the finally block **may not** execute even though the application as a whole continues." Interestingly, it [used to say](http://web.archive.org/web/20090209025948/http://java.sun.com/docs/books/tutorial/essential/exceptions/finally.html) "the finally block **will not** execute" – NullUserException Sep 14 '12 at 20:02
  • 1
    So essentially, there are only two things that actually prevent a finally from being called (programmatically). Either code that does not terminate in the try or catch blocks, or the immediate halting of the JVM. Other than that, it will execute. I guess my final question then is under what circumstances will thread death cause a finally block to execute or not? It certainly can't be luck of the draw, since I've run your code with the same results as well every time. But as NullUserException points out, it's both unexpected and contrary to the documentation. – asteri Sep 15 '12 at 15:37
  • AFAIK, the thread only really dies when it has completed. You can thrown any Throwable which can be caught and it won't prevent a finally being called. BTW: You can have sub-classes of Throwable which are not Error or Exception. :) – Peter Lawrey Sep 15 '12 at 16:18
  • Mr Lawrey, I'm curious to hear your thoughts on this extremely contrived [boundary case](http://stackoverflow.com/a/29923398/1050766). – Muel Apr 29 '15 at 18:33
  • @PeterLawrey : How can you mentioned here ""The finally block is always called when a Throwable is thrown."" I'm confused here because i have checked Throwable.class file in java source file but i did't get "finally block is always called when a Throwable is thrown." thsi type of code. – Onic Team Mar 18 '19 at 06:15
  • 1
    @VedPrakash The `finally` block is always called when the `try { }` exits normally, including when any `Throwable` is thrown. This is in the JLS, not the source for Throwable. – Peter Lawrey Mar 18 '19 at 09:52
  • 1
    @PeterLawrey: ((-,-)) – Onic Team Mar 18 '19 at 10:44
9

Infinite loop in the try block.

Corrupt RAM? Program no longer runs as written? I've actually debugged that once on a DOS machine.

Jeremy J Starcher
  • 23,369
  • 6
  • 54
  • 74
2

Testing the finally block in different statement in try block.

 public static void main(String [] args){

    try{
        System.out.println("Before Statement");
        /*** Statement ***/
        System.out.println("After Statement");
    }
    catch(Exception e){
    }
    finally{
        System.out.println("Finally is Executed");
    }

Statements in which finally block is executed are following:

  1. Thread.currentThread().interrupted();
  2. Thread.currentThread().destroy();
  3. Thread.currentThread().stop();
  4. Thread.sleep(10);
  5. Thread.currentThread().interrupt();
  6. Runtime.getRuntime().addShutdownHook(Thread.currentThread());
  7. If there is any exception occurred.
  8. If there is no exception.

Statements in which finally block is not executed are following:

  1. Thread.currentThread().suspend();
  2. System.exit(0);
  3. JVM crashed.
  4. Power to CPU chip goes off.
  5. OS kills JVM process.
  6. Runtime.getRuntime().exit(0);
  7. Runtime.getRuntime().halt(0);
Raman Gupta
  • 1,580
  • 15
  • 12
1

There is a chance of partial execution when finally itself throws an exception (or leads to an error)

Chris
  • 5,584
  • 9
  • 40
  • 58
1

One could be "A finally is a part of daeomon thread it may not be executed".

Tushar Paliwal
  • 301
  • 4
  • 11
  • This is misleading. Non-daemon threads also do not execute `finally` clauses on termination. – SusanW Jun 05 '17 at 18:27
1

The only times finally won't be called are:

if the power turns off

  1. if you call System.exit()
  2. if the JVM crashes first
  3. if there is an infinite loop in the try block
  4. if the power turns off
Virendra Singh
  • 297
  • 3
  • 9
0

I think when JVM exits suddenly due to any reason, that can be a cause the control will not enter into the the finally block and never execute.

JDGuide
  • 6,239
  • 12
  • 46
  • 64
0

You can make it a part of Daemon Thread. You may use the method setDaemon(boolean status) which is used to mark the current thread as daemon thread or user thread and exit the JVM as and when required. This will enable you exit the JVM before finally{} is executed.

eebbesen
  • 5,070
  • 8
  • 48
  • 70
Sambhav
  • 217
  • 2
  • 16
0

Another possible instance of a finally block never executing would be due to a design where the method returned before the try block was entered, as in the cases of some very bad code I've seen from time to time:

public ObjectOfSomeType getMeAnObjectOfSomeType() throws SomeHorrendousException {
    if (checkSomeObjectState()) {
        return new ObjectOfSomeType();
    }

    try {
        // yada yada yada...
    } catch (SomeHorrendousException shexc) {
        // wow, do something about this horrendous exception...
    } finally {
        // do some really important cleanup and state invalidation stuff...
    }

I know none of you would ever do this, so I hesitated to add this as a possible scenario, but thought, eh, it's Friday, what the heck ; )

idclaar
  • 688
  • 2
  • 7
  • 17