Java Reference
In-Depth Information
There is a neat feature snuck into this example, though, which makes Java's take on functional
programming very interesting. Did you see it? Note that the JdbcTemplate code that we called in both
Figures 1-11 and 1-12 was the same, and it is code that predates Java 8 and was written before lambdas were
a part of the Java spec. In one case, we had to specify the types that we were passing in through anonymous
inner classes; in the other case, we specified no types at all, but the compiler still figured out what types we
meant. The compiler not only figured out what interfaces we implemented, but also figured out the types of
the parameters that we were passing in, saving us substantially on code noise.
This capability is called type inference , and it's an extremely powerful programming language
feature. Historically, Java has done very little type inference. Generics introduced some very limited type
inference. Java 7's Project Coin gave us the empty generic (<>), such as in "List<Integer> ints = new
ArrayList<>();" , which is also an example of limited type inference. Java 8 introduces substantially
expanded type inference capabilities, especially when it comes to the Java's lambdas. In Java 8, any time that
you could pass an interface with a single method, you can pass in a function that is an implementation of
that method, and the compiler will infer what type you are talking about. 13
This type inference allows the API authors to use the rich, object-oriented style of API. The API can
provide hints to both the developer and the developer's tools through meaningful interfaces with useful
documentation and informative method names. The consumer of the API, meanwhile, can simply pass in
the functional implementations of these interfaces, just as we passed in a PreparedStatementSetter as
"ps -> ps.setString(1, "some value for baz")" . This means that Java gives us the best of both worlds.
We get our descriptive object-oriented API and leave the door open for reusable implementations; we also
enable users with strongly contextual logic to pass in succinct inline implementations. It's a very clever, very
useful, and very much underestimated feature of Java's functional programming capabilities.
The fact that legacy APIs are automatically promoted to support functional-style calls demonstrates
well that Java has always had functional programming capabilities. Before now, though, those capabilities
required messy syntactic glue; the dominant object-oriented paradigm got in the way of the functional
programming capabilities that exist within Java. With Java 8, the effective functional programming
techniques that existed beneath Java's object-oriented crust can finally come out.
Java 8 Is Not Just Syntactic Sugar
As far as we have seen, lambdas are just a more succinct way to express an anonymous inner class. While
this is both powerful and useful, it is hardly sufficient grounds for an entire book. Where is this revolution
that was advertised at the beginning of the chapter?
The revolution happens when these functions meet the new APIs scattered throughout the SDK. Most
of the changes are integrated into existing classes or packages, but there is one very striking addition. One
the new APIs is the introduction of the concept of a “stream,” which is kind of like an Iterator and kind of like
a grown-up Reader. Streams provide a huge stage for the functional syntax changes to perform their magic.
To tackle streams, let's return to the JdbcTemplate example. In that case, the second argument is a
RowMapper interface implementation, which is responsible for translating the results coming from the
database into a collection of the resulting objects. It is not possible at this point to filter out certain results;
attempts to do so involve hacks such as returning null and then filtering out the nulls at the end. It is also
not simple to partition the results or to calculate statistics from them. It's not easy to work with the elements
as a whole, and working with any given element requires loading the entire result set into memory. When
you think about it, both result sets and collections of models are really a rather awkward way to deal with
database results.
13 There are, of course, corner cases to this claim, especially when you're calling a method overloaded with similar interface
type structures. We will get into these boundary cases later.
 
Search WWH ::




Custom Search