JDK-5108147 : Extending finally to allow optional Throwable exception parameter
  • Type: Enhancement
  • Component: specification
  • Sub-Component: language
  • Affected Version: 5.0
  • Priority: P4
  • Status: Closed
  • Resolution: Won't Fix
  • OS: linux
  • CPU: x86
  • Submitted: 2004-09-28
  • Updated: 2011-10-31
  • Resolved: 2011-10-31
Related Reports
Relates :  
Relates :  
Description
Name: rmT116609			Date: 09/28/2004


A DESCRIPTION OF THE REQUEST :
A small extension to the Java language would solve the problem nicely:

    After the finally keyword, a (Throwable variable) declaration is optional.

If you provide the optional declaration, you must use Throwable as the type. The foregoing is motivated by the keep-it-simple principle. If you want to distinguish which subype of Throwable happened, you can use a standard instanceof if-else chain within the finally clause. (As before, and unlike catch, you can have only a single finally clause, not one for every exception type you want to match.)

The finally example in the JLS beatifully illustrates the utility of this feature.

No language incompatibility, no VM changes required.

Further explanation here:
http://Yost.com/computers/java/finally-throwable.html

  See also bug ID 4447072.

JUSTIFICATION :
1.  For debugging purposes, it would sometimes be nice to be able to write code that sits in a finally clause and peeks at signals, if any, as they go by. A classic example is found in the JLS itself (below).

2.  Sometimes you want to bulletproof code against anything that might go wrong, for example, in a transaction situation, like this:

    boolean success = false;
    try {
        doSomething();
        success = true;
    } finally {
        if (!success) {
            transaction.rollback();
        } else {
            transaction.commit();
        }
    }

This approach has two problems: the use of a temporary variable to direct program flow is clutter, and the finally code has no way to know which Throwable is involved, in case itM-^O����s interested.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
JLS Modifications:

14.19 The try statement

...

TryStatement:
	try Block Catches
	try Block Catchesopt FinallyClause

Catches:
	CatchClause
	Catches CatchClause

TryHandler:
	CatchClause
	ParameterizedFinallyClause

CatchClause:
	catch ExceptionParameter Block

FinallyClause:
	SimpleFinallyClause
	ParameterizedFinallyClause

SimpleFinallyClause:
	finally Block

ParameterizedFinallyClause:
	finally ExceptionParameter Block

ExceptionParameter:
	( FormalParameter )

...

The Block immediately after the keyword try is called the try block of the try statement.

A try statement may have catch clauses (also called exception handlers). A catch clause must have exactly one exception parameter. The Block immediately after the exception parameter is called the catch block of the catch clause or can be called a catch block of the try statement. The declared type of a catch clause exception parameter must be the class Throwable or a subclass of Throwable, or a compile-time error occurs.

A try statement may have a finally clause. The Block of a finally clause is called the finally block of the finally clause or the finally block of the try statement. A finally clause may be a simple finally clause or a parameterized finally clause. A simple finally clause is simply be the keyword finally followed by a Block. A parameterized finally block is the keyword finally followed by exactly one exception parameter, followed by a Block. The declared type of a parameterized finally clause exception parameter must be the class Throwable, or a compile-time error occurs.

A try handler is a generic term which can be used to refer to a catch clause or to a parameterized finally clause.

An exception parameter variable of a try handler must not have the same name as a local variable or parameter of the method or initializer Block immediately enclosing the try handler, or a compile-time error occurs.

The scope of a try handler exception parameter is the entire try handler Block.

Within a try handler Block, the name of the exception parameter may not be redeclared as a local variable of the directly-enclosing method or initializer Block, nor may it be redeclared as an exception parameter of a try handler in a try statement of the directly enclosing method or initializer Block, or a compile-time error occurs. However, an exception parameter may be shadowed (M-^O����6.3.1) anywhere inside a class declaration nested within the try handler Block.

It is a compile-time error if an exception parameter that is declared final is assigned to within its try handlerM-^O����s Block.

Exception parameters cannot be referred to using qualified names (M-^O����6.6), only by simple names.

Exception handlers are considered in left-to-right order: the earliest possible catch clause accepts the exception, receiving as its actual argument the thrown exception object.

A finally clause ensures that the finally block is executed after the try block and any catch block that might be executed, no matter how control leaves the try block or catch block.

A parameterized finally block executes with its actual parameter set either to the thrown exception object or to null if no exception was thrown.

...
14.19.2 Execution of try-catch-finally

...

class BlewIt extends Exception {
	BlewIt() { }
	BlewIt(String s) { super(s); }
}
class Test {
	static void blowUp() throws BlewIt {
		throw new NullPointerException();
	}
	public static void main(String[] args) {
		try {
			blowUp();
		} catch (BlewIt b) {
			System.out.println("BlewIt");
		} finally (Throwable th) {
			if (th != null) {
				System.out.println("Uncaught Exception " + th);
			}
		}
	}
}

produces the output:

Uncaught Exception java.lang.NullPointerException
java.lang.NullPointerException
	at Test.blowUp(Test.java:7)
	at Test.main(Test.java:11)

The NullPointerException (which is a kind of RuntimeException) that is thrown by method blowUp is not caught by the catch clause in the try statement in main, because a NullPointerException is not assignable to a variable of type BlewIt. The finally block inevitably executes, and the finally clauseM-^O����s th variable is set to the exception object, which is printed if it is non-null. After this, the thread executing main, which is the only thread of the test program, terminates because of an uncaught exception, which typically results in printing the exception name and a simple backtrace.
ACTUAL -
exception parameter disallowed in finally clause.

---------- BEGIN SOURCE ----------
try {
        doSomething();
    } finally (Throwable th) {
        if (th != null) {
            transaction.rollback();
            System.err.println("Transaction rolled back: " + th);
        } else {
            transaction.commit();
        }
    }
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
boolean success = false;
    try {
        doSomething();
        success = true;
    } finally {
        if (!success) {
            transaction.rollback();
        } else {
            transaction.commit();
        }
    }
(Incident Review ID: 315711) 
======================================================================

Comments
EVALUATION Proposals for new features in the Java programming language are no longer being accepted or maintained in the bug database at http://bugs.sun.com/. This also applies to proposals for new features in the Java Virtual Machine (that is, in the abstract JVM, as opposed to a JVM implementation like HotSpot). All proposals for new features should be made through the "JDK Enhancement - Proposal & Roadmap Process" described at http://openjdk.java.net/jeps/1. Consequently, this specific request to change the Java programming language will not be considered further. The bug database continues to accept and maintain submissions about technical errors in the design and specification of the Java programming language and the Java Virtual Machine.
31-10-2011

EVALUATION Another possibility for what you're writing today is: boolean success = false; try { doSomething(); success = true; } catch (TransactionException te) { success = false; transaction.rollback(); } finally { if (success) transaction.commit(); } (A minor benefit to this style of coding is that a tool could infer that 'success' is supposed to be set in every try/catch block, and could warn if you fall-through to finally without always assigning it.) As for the proposal: peeking at thrown exceptions would be quite neat. In try-finally(Throwable), it's obvious what the thrown exception is. But in try-catch-finally(Throwable), it isn't. Specifically, you say "A parameterized finally block executes with its actual parameter set either to the thrown exception object or to null if no exception was thrown." If a catch block throws an exception, does finally(Throwable t) offer that exception as t, or the initial exception thrown in the try block and caught? Either would be reasonable. The right answer is to offer both; see the reference to suppressed exceptions in 4988583.
10-11-2006