Functional Interfaces in Java – Functions

Introduction

In Java, a functional interface is an interface which has exactly one abstract method. Several functional interfaces were added to the JDK in Java 8. In this post, we will learn about the functional interface in Java for functions present as part of the java.util.function namespace.

Function

The Function is a functional interface in Java that represents a function that accepts one argument and returns a result back (a typical function). It has a single abstract method named apply. It takes in an argument of type T and returns a result of type R.

public interface Function<T, R> {
    R apply(T t);
}

Example: Let us create a function to convert string to an integer. 

Function<String, Integer> stringToInt = input -> {
    System.out.println("Converting string " + input + " to integer");
    return Integer.valueOf(input);
};

System.out.println(stringToInt.apply("5")); //5

The above code will print 5. 

When using method references, we can write the above as,
Function<String, Integer> stringToInt = Integer::valueOf;
System.out.println(stringToInt.apply("5")); //5

BiFunction

BiFunction is a function, but it takes in two arguments and produces a result. It is a two-arity specialization of the Function functional interface. Its signature is shown below:

public interface BiFunction<T, U, R> {
    R apply(T t, U u);
}

The two input arguments are of type T, and U and it returns a result of type R.

Let us define a BiFunction which takes two integers as strings, converts them to integers and adds them.

BiFunction<String, String, Integer> convertAndAdd = (input1, input2) ->
                Integer.valueOf(input1) + Integer.valueOf(input2);
System.out.println(convertAndAdd.apply("5", "2")); //7

UnaryOperator

UnaryOperator is like a function where it takes an argument and returns a result, but both the argument and the result are the same type. It’s signature is:

public interface UnaryOperator<T> extends Function<T, T> {
}

Let us define a UnaryOperator which takes a string and returns a string that is upper-case of the passed string.

UnaryOperator<String> upperCase = String::toUpperCase;
System.out.println(upperCase.apply("test")); //TEST

We used method reference to define the UnaryOperator in the above example. The above example is equivalent to a Function<String, String>.

BinaryOperator

BinaryOperator extends BiFunction where all operands are of the same type. In other words, it takes two arguments of the same type and returns a result of that type.

public interface BinaryOperator<T> extends BiFunction<T,T,T> {
}

The below code shows a BinaryOperator which takes two strings and concatenates them by separating them with a hyphen.

BinaryOperator<String> concat = (input1, input2) -> input1 + "-" + input2;
System.out.println(concat.apply("ab", "cd")); //ab-cd

The above example is equivalent to a BiFunction<String, String, Integer>.

Primitive specialization for Function

Function has three special functional interfaces for the primitives intlong and double.

IntFunction

This is a Function (does not extend Function) which accepts a primitive int and returns a result (which can be of any type). Thus it is a int-consuming primitive specialization for Function.

IntFunction<String> intToString = String::valueOf;
System.out.println(intToString.apply(5)); //5

The above creates an IntFunction to convert a primitive int to a String.

LongFunction and DoubleFunction

Similart to the IntFunction, LongFunction and DoubleFunction are long and double primitive specialization for Function, respectively. They take in a long and a double respectively and return some result (any type).

LongFunction<String> longToString = String::valueOf;
System.out.println(longToString.apply(123L)); //123

DoubleFunction<String> doubleToString = String::valueOf;
System.out.println(doubleToString.apply(4.56)); //4.56

The above example converts a long and a double to Strings respectively.

Primitive specialization for UnaryOperator

Now let us look at the UnaryOperator specialization for primitives.

IntUnaryOperator

The IntUnaryOperator represents a function which takes a single primitive int and produces a new primitive integer. Note that it doesn’t return an arbitrary type like a Function. The functional interface method is applyAsInt.

public interface IntUnaryOperator {
    int applyAsInt(int operand);
}
IntUnaryOperator addOneToInt = integer -> integer + 1;
System.out.println(addOneToInt.applyAsInt(5)); //6

The above code created a IntUnaryOperator which takes a primitive int and returns a new primitive int adding one to the passed input.

LongUnaryOperator, DoubleUnaryOperator

The LongUnaryOperator and DoubleUnaryOperator are primitive specializations for UnaryOperator. 

  • LongUnaryOperator takes a long and produces a long result.
  • DoubleUnaryOperator takes a double and produces a double result.

LongUnaryOperator has a single abstract method named applyAsLong and it is applyAsDouble for DoubleUnaryOperator.

LongUnaryOperator addOneToLong = longVal -> longVal + 1;
System.out.println(addOneToLong.applyAsLong(123L)); //124

DoubleUnaryOperator addOneToDouble = doubleVal -> doubleVal + 1;
System.out.println(addOneToDouble.applyAsDouble(4.56)); //5.56

Primitive specialization for BinaryOperator

BinaryOperation also has three specializations for primitives viz., IntBinaryOperator, LongBinaryOperator and DoubleBinaryOperator.

IntBinaryOperator

The IntBinaryOperator has a method called applyAsInt which takes two primitive integers and produces a primitive int as result. It’s method signature is shown below:

public interface IntBinaryOperator {
    int applyAsInt(int left, int right);
}
//Adds two primitive ints
IntBinaryOperator addInts = (int1, int2) -> int1 + int2; //Integer::sum;
System.out.println(addInts.applyAsInt(1, 2)); //3

LongBinaryOperator and DoubleBinaryOperator

LongBinaryOperator and DoubleBinaryOperator are long and double specializations for BinaryOperator. Examples are shown below:

LongBinaryOperator addLongs = (long1, long2) -> long1 + long2; //Long::sum;
System.out.println(addLongs.applyAsLong(10L, 20L)); //30

DoubleBinaryOperator addDoubles = (double1, double2) -> double1 + double2; //Double::sum;
System.out.println(addDoubles.applyAsDouble(1.1, 2.3)); //3.4

Conversion from a type to primitive

Let us now see the functions that exist for converting an arbitrary type to the primitive values. 

ToIntFunction and ToIntBiFunction

The ToIntFunction converts an object (any type) to an integer. ToIntBiFunction takes two arguments and returns an integer. Their method signatures are:

public interface ToIntFunction<T> {
    int applyAsInt(T value);
}

public interface ToIntBiFunction<T, U> {
    int applyAsInt(T t, U u);
}
ToIntFunction<String> stringToIntFunc = string -> Integer.valueOf(string); // Integer::valueOf
System.out.println(stringToIntFunc.applyAsInt("5")); //5

In the above code, we have a ToIntFunction which takes a integer as a string and returns an integer. The auto-boxing is handled automatically (converting from Integer to primitive integer).

ToIntBiFunction<Integer, String> intAndStringToInt = (integer, string) -> 
        integer + Integer.valueOf(string);
System.out.println(intAndStringToInt.applyAsInt(1, "5")); //6

Above we have a ToIntBiFunction which takes a Integer (object) and a String. It converts the String to Integer and adds it to the first argument and returns it.

ToLongFunction and ToLongBiFunction

  • The ToLongFunction takes an argument and returns a primitive long value.
  • The ToLongBiFunction takes two arguments and returns a primitive long value.
ToLongFunction<String> stringToLongFunc = string -> Long.valueOf(string); // Long::valueOf
System.out.println(stringToLongFunc.applyAsLong("123")); //123
ToLongBiFunction<Integer, String> intAndStringToLong = (integer, string) ->
        integer + Integer.valueOf(string);
System.out.println(intAndStringToLong.applyAsLong(1, "5")); //6

ToDoubleFunction and ToDoubleBiFunction

  • The ToDoubleFunction takes an argument and returns a primitive double value.
  • The ToDoubleBiFunction takes two arguments and returns a primitive double value.
ToDoubleFunction<String> stringToDoubleFunc = string -> Double.valueOf(string); // Double::valueOf
System.out.println(stringToDoubleFunc.applyAsDouble("5.1")); //5.1
ToDoubleBiFunction<Integer, String> intAndStringToDouble = (integer, string) ->
        integer + Integer.valueOf(string);
System.out.println(intAndStringToDouble.applyAsDouble(1, "5")); //6.0

Conversion among primitives

There are few functional interfaces which has the methods to convert one primitive value to others.

  • An integer to a long or double.
  • An long to an integer or double.
  • And a double to an integer or long.

IntToLongFunction and IntToDoubleFunction

The IntToLongFunction converts from a primitive integer to a primitive long whereas the IntToDoubleFunction converts from a primitive integer to a primitive double.

IntToLongFunction intToLong = integer -> (long) integer;
System.out.println(intToLong.applyAsLong(5)); //5

IntToDoubleFunction intToDouble = integer -> (double) integer;
System.out.println(intToDouble.applyAsDouble(5)); //5.0

LongToIntFunction and LongToDoubleFunction

  • LongToIntFunction converts a primitive long to a primitive int.
  • LongToDoubleFunction converts a primitive long to a primitive double.
LongToIntFunction longToInt = longVal -> (int) longVal;
System.out.println(longToInt.applyAsInt(123L)); //123

LongToDoubleFunction longToDouble = longVal -> (double) longVal;
System.out.println(longToDouble.applyAsDouble(123L)); //123.0

DoubleToIntFunction and DoubleToLongFunction

  • DoubleToIntFunction converts a primitive double to a primitive int.
  • DoubleToLongFunction converts a primitive double to a primitive long.
DoubleToIntFunction doubleToInt = doubleVal -> (int) doubleVal;
System.out.println(doubleToInt.applyAsInt(1.1)); //1

DoubleToLongFunction doubleToLong = doubleVal -> (long) doubleVal;
System.out.println(doubleToLong.applyAsLong(1.1)); //1

Conclusion

This concludes the post on the Java functional interfaces for Function in the java.util.function namespace.

Leave a Reply