Primitive Type Specializations of BiFunction<T, U, R>
Table 13.8 shows that the BiFunction<T, U, R> interface has three primitive type twoarity generic specializations to int, long, and double, but they do not define any default methods for creating compound functions. The specializations are named ToPrimBiFunction<T, U>, where Prim is either Int, Long, or Double. These two-arity generic functions have the functional method applyAsPrim: (T, U) -> primitive, where primitive is an int, long, or double—the function takes two arguments of type T and U, and returns a result of a primitive type.
In the example below, the addIntStrs two-arity function parses two strings as int values and returns the sum of the values.
ToIntBiFunction<String, String> addIntStrs
= (s1, s2) -> Integer.parseInt(s1) + Integer.parseInt(s2);
System.out.println(“10 + 20 = ” + addIntStrs.applyAsInt(“10”, “20”));
// 10 + 20 = 30
13.10 Extending Function<T,T>: UnaryOperator<T>
Table 13.9 shows that the UnaryOperator<T> interface extends the Function<T, T> interface for the special case where the types of the argument and the result are the same. It inherits the functional method apply() from the Function<T, T> interface. It also inherits the default methods compose() and andThen() from its superinterface Function<T, T>, but note that these methods return a Function<T,T>, and not a UnaryOperator<T>.
Functions where the argument and the result type are the same can easily be refactored to use the UnaryOperator<T> interface.
UnaryOperator<Double> area = r -> Math.PI * r * r;
System.out.printf(“Area of circle, radius %.2f: %.2f%n”, 10.0, area.apply(10.0));
// Area of circle, radius 10.00: 314.16
UnaryOperator<Double> milesToKms = miles -> 1.6 * miles;
System.out.printf(“%.2fmi = %.2fkm%n”, 24.0, milesToKms.apply(24.0));
// 24.00mi = 38.40km
The List.replaceAll(UnaryOperator<E>) method can be used to replace each elements in the list with the result of applying the specified unary operator to that element. The method replaces all strings in the list team with their uppercase versions.
List<String> team = Arrays.asList(“Tom”, “Dick”, “Harriet”);
UnaryOperator<String> toUpper = str -> str.toUpperCase();
team.replaceAll(toUpper); // [TOM, DICK, HARRIET]
Since the UnaryOperator<T> interface is a subinterface of the Function<T, T> interface and inherits the default methods compose() and andThen(), creating compound unary operators is no different from creating compound functions.
UnaryOperator<String> f = s -> s + “-One”;
UnaryOperator<String> g = s -> s + “-Two”;
System.out.println(f.compose(g).apply(“Three”)); // Three-Two-One
System.out.println(f.andThen(g).apply(“Three”)); // Three-One-Two
Table 13.9 Unary Operators
Functional interface (T, U, and R are type parameters) | Functional method | Default methods unless otherwise indicated |
UnaryOperator<T> extends Function<T,T> | apply: T -> T | compose(), andThen(), static identity() |
IntUnaryOperator | applyAsInt: int -> int | compose(), andThen() |
LongUnaryOperator | applyAsLong: long -> long | compose(), andThen() |
DoubleUnaryOperator | applyAsDouble: double -> double | compose(), andThen() |