Today, a tantalizing announcement by Mark Reinhold about closures in Java 7 has made its way through the twittersphere.
On the same day, Neal Gafter updated his closure proposal (known as the BGGA proposal, named after the initials of Bracha, Gafter, Gosling, and von der Ahé, and not at all related to the B. G. G. A. organization).
Presumably the timing is not a coincidence.
The proposal is a bit technical, so I thought I'd translate my understanding of it into some use cases. Here goes.
pool.submit(#() { for (int i = 1; i < 1000000; i++) doWork(i) });
Here, the #() { ... }
denotes a function literal.
#()
indicates that the function has no parameters. (I guess
the return type is inferred.) The function body is a block, enclosed in
braces.
If you squint really hard, the #
looks like a λ
:-)
The function object is automatically converted to a
Runnable
because the Runnable
interface has a
single method, also with no parameters.
button.addActionListener(#(ActionEvent e) System.out.println("Hi!));
This is pretty much the same as the previous example, except that you
can have a single expression after the #(...)
, and then you
don't use braces.
It is certainly an improvement over
button.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { System.out.println("Hi!"); } } );
Here we sort a string list by increasing length:
Collections.sort(strings, #(String a, String b) a.length() - b.length());
which can also be written as
Collections.sort(strings, #(String a, String b) { return a.length() - b.length(); });
Note that you need a return
and a ;
if you use
a block instead of an expression.
java.util.concurrent
lock:
withLock(myLock, #() { if (account2.getBalance() < amount) return; account1.deposit(amount); account2.withdraw(amount); });
Here we assume that some friendly soul has written a
withLock
method. You can find the code for that method in
Neal's proposal. I am purposefully not reproducing that code
because it will frighten small children. But so what—it's something
that only library writers worry about.
This is similar to my first example, except for the return statement. In
prior versions of the BGGA proposal, return
would return from
the method containing the withLock
method. That was nifty in a
way—it allowed new control statements that feel just like the
built-in ones. But it was also potentially confusing. Now
return
simply returns from the function, and execution
continues with the statement following withLock
.
double amount = 1000; Collection<Account> result = filter(accounts, #(Account a) a.getBalance() < amount);
Again, I assume that some friendly soul has written a
filter
method.
Note that the closure can reference the amount
variable
from the enclosing scope. It doesn't have to be final
because
I am never assigning to it after I initialize it.
@Shared int clickCount = 0;
button.addActionListener(#(ActionEvent e) { clickCount++; });
The @Shared
is required because the clickCount
variable is mutated.
By the way, this is another one of those things that is incredibly
convoluted in Java without closures. int
is a primitive type
and Integer
is immutable. The path of least resistance is
final int[] clickCount = new int[1]; button.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { clickCount[0]++; } } );
Overall, I like it. The simple things are simple, and there don't seem any hidden pitfalls.
Of course, someone out there will say "Oh my, oh my, that
#(ActionEvent e){...}
makes my head explode. It's not cuddly and
comfortable like addActionListener(new ActionListener() { public void
ActionPerformed(ActionEvent e) {...}});
”.
To which I'll say “I rest my case”.
More interestingly, someone on the Project Coin mailing list tried to muddy the waters by asking how this feature interacts with other new features of Java 7, like
try (Closeable c = #() { System.out.println("YOUR HEAD A SPLODE"); }) { // ... }
Ok, that means that the close
method of c
will be
invoked in the finally
clause, and that method is set to the
#() {...}
. What's so hard about that?
If this is indeed to come to pass in Java 7 (and I have absolutely no inside knowledge whether it will), I am willing to wait a bit longer. What do you think?