Primitive Type Specializations of BiFunction – Functional-Style Programming

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.

Click here to view code image

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.

Click here to view code image

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.

Click here to view code image

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.

Click here to view code image

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 methodDefault methods unless otherwise indicated
UnaryOperator<T> extends Function<T,T>apply: T -> Tcompose(), andThen(), static identity()
IntUnaryOperatorapplyAsInt: int -> intcompose(), andThen()
LongUnaryOperatorapplyAsLong: long -> longcompose(), andThen()
DoubleUnaryOperatorapplyAsDouble: double -> doublecompose(), andThen()

Leave a Comment