Java Reference
In-Depth Information
Listing 2-16.
Using Operator Types to Capture Familiar Lambdas
UnaryOperator<String> upperCase = str -> str.toUpperCase();
BinaryOperator<String> concat = (left,right) -> left + right;
Lambdas as Predicates
This topic opened up with a story about the usefulness of predicate types. Java has implemented predicates
as a special case of the Function functional interface: specifically, one that takes any type and returns a
boolean
. This is an extremely common functional type that simply returns true or false and that is used any
time your functional program has a conditional branch, a filter, or a guard. We demonstrate a basic “not
null
or empty” check for a
String
in Listing 2-17.
Listing 2-17.
Predicate Lambda Checking if a String Is Null or Empty
Predicate<String> notNullOrEmpty = s -> s != null && s.length() > 0;
Lambdas with Primitive Arguments
In Listing 2-8, we saw a
Supplier
that returned a given integer value,
1
. However, that value was returned
as an object extending
Number
, not as the primitive value. This is an example of a “boxed integer,” and the
implicit conversion that just happened is called “autoboxing.” Many developers have an allergy to boxing
primitive values, even though the real performance impact of boxing is largely negated through compiler
optimizations, standard library performance tricks, and Java's excellent garbage collector. However, there are
still cases when the performance cost of autoboxing is significant; and if you are dealing with a lot of integer
values, you might as well avoid the autoboxing. For those cases, you can create lambdas that use primitives.
There are primitive functional interfaces for the
double
,
int
, and
long
primitive types. There are also
functional interfaces that take one of those primitive types and produce another of those primitive types,
such as
DoubleToIntFunction
. Java provides primitive versions of most of the functional interfaces. The most
notable missing entry in this list is
ObjIntBifunction
: I don't know why Java didn't provide this interface.
While we only take a look at the
int
interfaces in Listing 2-18, rest assured, there are corresponding
versions of each of these interfaces for the
double
and
long
primitive types, too. Just replace
"Int"
with
"Double"
in the class name, and you have the corresponding functional type for the
double
type.
Listing 2-18.
Predicate Lambda Checking if a String Is Null or Empty
IntFunction<String> intToString = i -> Integer.toString(i);
ToIntFunction<String> parseInt = str -> Integer.valueOf(str);
IntPredicate isEven = i -> i % 2 == 0;
ToIntBiFunction<String,String> maxLength =
(left,right) -> Math.max(left.length(), right.length());
IntConsumer printInt = i -> System.out.println(Integer.toString(i));
ObjIntConsumer<String> printParsedIntWithRadix =
(str,radix) -> System.out.println(Integer.parseInt(str,radix));
IntSupplier randomInt = () -> new Random().nextInt();
IntUnaryOperator negateInt = i -> -1 * i;
IntBinaryOperator multiplyInt = (x,y) -> x*y;
IntToDoubleFunction intAsDouble = i -> Integer.valueOf(i).doubleValue();
DoubleToIntFunction doubleAsInt = d -> Double.valueOf(d).intValue();
IntToLongFunction intAsLong = i -> Integer.valueOf(i).longValue();
LongToIntFunction longAsInt = x -> Long.valueOf(x).intValue();