Closures for Java (v0.6b)

Neal Gafter and Peter von der Ahé

Building on lambda expressions and exception type parameters described in the companion document v0.6a, we describe support for control abstractions, which are APIs that can abstract patterns of control. These correspond to blocks and lambda expressions in languages such as Ruby, Smalltalk, and Scala.

Block Expressions

We extend the syntax of a parenthesized expression to allow it to be preceded by a sequence of statements. The grammar for a parenthesized expression [JLS 15.8.5] is changed to:

( BlockStatementsopt Expression )

Note that the existing syntax for a parenthesized expression is a special case of this.

Meaning of Expressions: The specification for a parenthesized expression is modified to describe its new execution semantics: The block statements (if any) are executed in sequence, from left to right.  The result of the block expression is:

Definite Assignment: The definite assignment rules for this construct are almost identical to that for the block statement.  The definite assignment state before the first block statement is the definite assignment state before the parenthesized expression. The definite assignment state before the subexpression is the definite assignment state following the last block statement. The definite assignment state after the parenthesized expression is the definite assignment state after the contained expression.

Exception Checking: A parenthesized expression can throw exception type E if any statement or expression immediately contained in it can throw E.

Scoping: Local variables and classes declared by an immediately contained statement is in scope until the end of the parenthesized expression.

Control invocation syntax

A new invocation statement syntax is added to make closures convenient for control abstraction:

foropt Primary ( FormalParameters : ExpressionListopt ) Statement
foropt Primary ( ExpressionListopt ) Statement

This syntax is a shorthand for the following statement:

Primary ( ExpressionList, # ( FormalParametersopt ) ( Statement (Void)null ) );

(See the later section loop abstractions for the meaning of the optional for keyword) This syntax makes some kinds of function-receiving APIs more convenient to use to compose statements.

We could use the shorthand to write our previous example (0.6a) this way

withLock(lock) {

Another example of its use would be a an API that closes a after a user-supplied block of code, discarding any exception from Closeable.close:

<R, T extends, throws E>
R with(T t, #R(T) throws E block) throws E {
    try {
        return block.invoke(t);
    } finally {
        try { t.close(); } catch (IOException ex) {}

We could use the shorthand with this API to close a number of streams at the end of a block of code:

with(FileReader in : makeReader()) with(FileWriter out : makeWriter()) {
    // code using in and out

Loop Abstractions

The specification supports writing methods that act as control statements, but when used to support loops the API implementor should be able to specify that the controlled statement should capture the meaning of break and continue in a way analogous to the built-in loop statements. For this purpose we allow the for keyword at the beginning of a control invocation statement (see above), and introduce the use of the keyword for as a modifier on method declarations:

foropt Identifier ( FormalParamterListopt )

An overriding or implementing method must be declared with the keyword for if and only if the method being overridden or implemented was declared with the keyword for.

A control invocation statement must use the for keyword if and only if the method being invoked was declared with the keyword for.

Within the controlled statement of a control invocation statement using the keyword for:

Example: The following illustrates a method used to loop through the key-value pairs in a map. The method

<K,V,throws X>
void for eachEntry(Map<K,V> map, #void(K,V) throws X} block)
        throws X {
    for (Map.Entry<K,V> entry : map.entrySet()) {
        block.invoke(entry.getKey(), entry.getValue());


allows us to rewrite this

void test(Map<String,Integer> map) {
    for (Map.Entry<String,Integer> entry : map.entrySet()) {
        String name = entry.getKey();
        Integer value = entry.getValue();
        if ("end".equals(name)) break;
        if (name.startsWith("com.sun.")) continue;
        System.out.println(name + ":" + value);


like this

void test(Map<String,Integer> map) {
    for eachEntry(String name, Integer value : map) {
        if ("end".equals(name)) break;
        if (name.startsWith("com.sun.")) continue;
        System.out.println(name + ":" + value);


Unmatched Control Transfers

Control transfers by return, break, or continue can, within an expression lambda, jump to a target outside the body of the lambda. It is possible for such code to be invoked at a time that the target of the transfer is not on the call stack of the current thread. In this case an exception of type UnmatchedTransferException is thrown.

package java.lang;

 * Exception thrown when a transfer from within a lambda doesn't have
 * a matching frame on the stack of the current thread.
 * @author gafter
public class UnmatchedTransferException extends RuntimeException {
     * This constructor is used by compiler-generated code.
    public UnmatchedTransferException(Jump jump);

     * Returns the thread in which the transfer target is executing.
    public Thread thread();

     * Return the exception to be thrown to cause the transfer to
     * occur.  This can be used to implement concurrent APIs
     * that support control transfers.  See, for example,
     * and
    public RuntimeException transfer();


The authors would like to thank the following people whose discussions and insight have helped us craft, refine, and improve this proposal:

C. Scott Ananian, Lars Bak, Cedric Beust, Joshua Bloch, Gilad Bracha, Martin Buchholz, Alex Buckley, Maurizio Cimadamore, Ricky Clarkson, Stephen Colebourne, Danny Coward, Luc Duponcheel, Erik Ernst, Rémi Forax, James Gosling, Christian Plesner Hansen, Cay Horstmann, Kohsuke Kawaguchi, Danny Lagrouw, Doug Lea, Peter Levart, "crazy" Bob Lee, Mark Mahieu, Niklas Matthies, Tony Morris, Martin Odersky, Terence Parr, Tim Peierls, Cris Perdue, John Rose, Ken Russell, Stefan Schulz, Guy Steele, Mads Torgersen, Zdenek Tronicek, Jan Vitek, and Dave Yost.

Changes in this revision (0.6) compared to BGGA 0.5

Changes that need to go into the prototype

Creative Commons License
Closures for Java by Neal Gafter and Peter von der Ahé is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.