Chapter 2 ■ Understanding Lambdas in Java 8
15
Note that we have a different type: the method signature that we want is no arguments and returning
Number, but Function is an interface whose only method has a signature with a single argument, and so
we need a different interface to represent this different signature.
4
For lambdas without arguments, the
functional interface is Supplier: the name was picked because they are used to supply values without
needing any input.
It is also possible to have multi-argument lambdas. At this point, the syntax should be predictable: we
will again use parentheses to demarcate the argument list, and we will again use type inference to specify
our types. An example of a two-argument function (called a bifunction) is given in Listing 2-9. The functional
type for these kinds of methods is BiFunction. Java’s SDK does not contain support for lambdas with more
than two arguments, because you really shouldn’t be using lambdas for that kind of complex case. If you
really want to have a lambda with lots of arguments, see “Lambdas as Interface Implementations” below
for how to handle that case. It is also worth noting that you cannot use varargs (e.g., String... strings)
as a lambda argument type: you have to treat the varargs parameter as an array. This sad fact is due to an
unfortunate limitation in Java’s type system.
5
The good news is that there are limited cases when you need
to have three or more arguments or varargs: zero-, one-, and two-argument functions handle most of your
cases. Streams (covered in the next chapter) and currying (covered in the next subsection) provide for almost
all these cases.
Listing 2-9. String Concatenation Bifunction
BiFunction<String, String, String> concat = (a, b) -> a + b;
Partial Function Application and Mr. Curry’s Verb
Every culture and subculture has its own language that identifies members of the tribe. One of the weird
tribal codewords in the functional programming tribe is “currying,” which is a verb coined after the logician
Haskell Curry. To understand what it means to curry a function and why one might want to do it, let’s start in
another place: partial function application.
Partial function application is exactly what it says it is: the application of part of a function. Consider,
for instance, the string concatenation bifunction given in Listing 2-9. What if you wanted to concatenate the
same thing to the front of a number of strings? Repeating yourself is one of the cardinal sins of programming
(“DRY”), and passing the same argument in over and over and over again is certainly repeating yourself.
What you want is a version of the bifunction with the first argument fixed to a certain value. Fixing that first
argument is called “applying” the argument, and since you’re only fixing the first of two possible arguments,
the application is “partial.” In Listing 2-10, we demonstrate what we are doing when we do partial function
application: we are creating a Function that applies a fixed first argument to a BiFunction. The resulting
Function can then be applied over and over again to multiple arguments. In Listing 2-11, we see how this
is implemented: although Java does not provide a built-in partial function application method, it is simple
to write one. We simply accept the bifunction that we want to apply along with the first argument, and then
return a function that calls back to that bifunction with the first argument already set.
4
This is one of the places where Java is decidedly not a functional language: function types are still communicated via
interfaces, instead of being intrinsic within the language itself.
5
Some people claim that vargargs in lambdas are unnecessary, and that attempting to use them is a sign that you are doing
something wrong. If you want to see both the good and the bad of vararg lambdas, see JavaScript’s arguments object
and the places where it is directly used.