1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
# A New Kind of Java
Java 8 is almost here. You can [play with the early access
previews](http://jdk8.java.net/download.html) right now, and I think you
should, even if you don't like Java very much. There's so much _potential_ in
there.
## The “One More Thing”
The Java 8 release comes with a slew of notable library improvements: the new
[`java.time`](http://openjdk.java.net/jeps/150) package, designed by the folks
behind the extremely capable Joda time library; [reflective
access](http://openjdk.java.net/jeps/118) to parameter names; [Unicode
6.2](http://openjdk.java.net/jeps/133) support; numerous others. But all of
these things are dwarfed by the “one last thing”:
**Lambdas**.
## Ok, So..?
Here's the thing: all of the “modern” languages that see regular use - C#,
Python, Ruby, the various Lisps including Clojure, and Javascript - have
language features allowing easy creation and use of one-method values. In
Python, that's any object with a `__call__` method (including function
objects); in Ruby, it's blocks; in Javascript, it's `function() {}`s. These
features allow _computation itself_ to be treated as a value and passed
around, which in turn provides a very powerful and succinct mechanism for
composing features.
Java's had the “use” side down for a long time; interfaces like `Runnable` are
a great example of ways to expose “function-like” or “procedure-like” types to
the language without violating Java's bureaucratic attitude towards types and
objects. However, the syntax for creating these one-method values has always
been so verbose and awkward as to discourage their use. Consider, for example,
a simple “task” for a thread pool:
pool.execute(new Runnable() {
@Override
public void run() {
System.out.println("Hello, world!");
}
});
(Sure, it's a dumb example.)
Even leaving out the optional-but-recommended `@Override` annotation, that's
still five lines of code that only exist to describe to the compiler how to
package up a block as an object. Yuck. For more sophisticated tasks, this sort
of verbosity has lead to multi-role “event handler” interfaces, to amortize
the syntactic cost across more blocks of code.
With Java 8's lambda support, the same (dumb) example collapses to
pool.execute(() -> System.out.println("Hello, world"));
It's the same structure and is implemented very similarly by the compiler.
However, it's got much greater informational density for programmers reading
the code, and it's much more pleasant to write.
If there's any justice, this will completely change how people design Java
software.
## Event-Driven Systems
As an example, I knocked together a simple “event driven IO” system in an
evening, loosely inspired by node.js. Here's the echo server I wrote as an
example application, in its entirety:
package com.example.onepointeight;
import java.io.IOException;
public class Echo {
public static void main(String[] args) throws IOException {
Reactor.run(reactor ->
reactor.listen(3000, client ->
reactor.read(client, data -> {
data.flip();
reactor.write(client, data);
})
)
);
}
}
It's got a bad case of Javascript “arrow” disease, but it demonstrates the
expressive power of lambdas for callbacks. This is built on NIO, and runs in a
single thread; as with any decent multiplexed-IO application, it starts to
have capacity problems due to memory exhaustion well before it starts to
struggle with the number of clients. Unlike Java 7 and earlier, though, the
whole program is short enough to keep in your head without worrying about the
details of how each callback is converted into an object and without having to
define three or four extra one-method classes.
## Contextual operations
Sure, we all know you use `try/finally` (or, if you're up on your Java 7,
`try()`) to clean things up. However, context isn't always as tidy as that:
sometimes things need to happen while it's set up, and un-happen when it's
being torn down. The folks behind JdbcTemplate already understood that, so you
can already write SQL operations using a syntax similar to
User user = connection.query(
"SELECT login, group FROM users WHERE username = ?",
username,
rows -> rows.one(User::fromRow)
);
Terser **and** clearer than the corresponding try-with-resources version:
try (PreparedStatement ps = connection.prepare("SELECT login, group FROM users WHERE username = ?")) {
ps.setString(1, username);
try (ResultSet rows = rs.execute()) {
if (!rows.next())
throw new NoResultFoundException();
return User.fromRow(rows);
}
}
## Domain-Specific Languages
I haven't worked this one out, yet, but I think it's possible to use lambdas
to implement conversational interfaces, similar in structure to “fluent”
interfaces like
[UriBuilder](http://docs.oracle.com/javaee/6/api/javax/ws/rs/core/UriBuilder.html).
If I can work out the mechanics, I'll put together an example for this, but
I'm half convinced something like
URI googleIt = Uris.create(() -> {
scheme("http");
host("google.com");
path("/");
queryParam("q", "hello world");
});
is possible.
|