Functional interface

  • should have single abstract method
  • such an interface is also called Single Abstract Method (SAM)
  • @FunctionalInterface is optional but recommended and used to mark functional interfaces and to raise a compile-time error if an interface doesn’t satisfy the requirements of a functional interface.
  • static and default methods are allowed in functional interfaces because these methods are not abstract
  • The name of the method is arbitrary and can be anything, and you need to invoke the function using the name defined in the functional interface
@FunctionalInterface
public interface GreetingMessage {
 
	public abstract void greet(String name)
}
  • Functional Interfaces can inherit another interface if it contains only static or default methods in it. how about private???

Implement functional interface

Using lambdas

  • anonymous function
GreetingMessage gm = (String name) -> {
	System.out.println("Hello " + name);
}
 
gm.greet("Kevin");

Using method references

  • Can be used for
    • static method - Class::staticMethod
    • instance method - obj::instanceMethod
    • instance method of a ObjectType - ObjectType::instanceMethod
    • constructor reference - ClassName::new
 
// Both below are same
(Square square) -> { return square.calculateArea() }
Square::calculateArea
 
// static method
(args) -> Class.staticMethod(args)
Class::staticMethod
 
// instance method
(args) -> obj.instanceMethod(args)
obj::instanceMethod
 
// instance method of a ObjectType
(obj, args) -> obj.instanceMethod(args)
ObjectType::instanceMethod
 
 
// constructor references
(args) -> new ClassName(args)
ClassName::new

Using Anonymous class

Func<Long, Long> square = new Func<Long, Long>() {
    @Override
    public Long apply(Long val) {
        return val * val;
    }
};

Built in Functional Interfaces

  • package: java.util.function
  • They can be classified as follows:
    • functions: accept argument produce result
      • example: Function<T, R>
      • apply()
    • operators: produce result of the same type as argument
      • example: UnaryOperator<T>
      • apply()
    • predicates: accept argument and return boolean
      • example: Predicate<T>
      • test()
      • more methods: and(), negate(), or(), not()
    • suppliers: accept nothing and return values
      • example: Supplier<T>
      • get()
    • consumers: accept argument and return no result
      • example: Consumer<T>
      • accept()
      • more methods: andThen()

Functions

// String to Integer function
Function<String, Integer> converter = Integer::parseInt;
converter.apply("1000"); // the result is 1000 (Integer)
 
// String to int function
ToIntFunction<String> anotherConverter = Integer::parseInt;
anotherConverter.applyAsInt("2000"); // the result is 2000 (int)
 
// (Integer, Integer) to Integer function
BiFunction<Integer, Integer, Integer> sumFunction = (a, b) -> a + b;
sumFunction.apply(2, 3); // it returns 5 (Integer)

Operators

// Long to Long multiplier
UnaryOperator<Long> longMultiplier = val -> 100_000 * val;
longMultiplier.apply(2L); // the result is 200_000L (Long)
 
// int to int operator
IntUnaryOperator intMultiplier = val -> 100 * val;
intMultiplier.applyAsInt(10); // the result is 1000 (int)
 
// (String, String) to String operator
BinaryOperator<String> appender = (str1, str2) -> str1 + str2;
appender.apply("str1", "str2"); // the result is "str1str2"

Predicates

// Character to boolean predicate
Predicate<Character> isDigit = Character::isDigit;
isDigit.test('h'); // the result is false (boolean)
 
// int to boolean predicate
IntPredicate isEven = val -> val % 2 == 0;
isEven.test(10); // the result is true (boolean)

Suppliers

Supplier<String> stringSupplier = () -> "Hello";
stringSupplier.get(); // the result is "Hello" (String)
 
BooleanSupplier booleanSupplier = () -> true;
booleanSupplier.getAsBoolean(); // the result is true (boolean)
 
IntSupplier intSupplier = () -> 33;
intSupplier.getAsInt(); // the result is 33 (int)

Consumers

// it prints a given string
Consumer<String> printer = System.out::println;
printer.accept("!!!"); // It prints "!!!"

Misc functions

  • Runnable
    • Does not return or throw anything
    • package: java.lang
    • Runnable
    • void run()
  • Callable
    • Can return value or throw exception
    • package: java.util.concurrent
    • Callable<V>
    • V call() throws Exception
  • Comparator
    • Return: negative (), zero (), positive ()
    • package: java.util
    • Comparator<T>
    • int compare(T o1, T o2)

Have you ever implemented a functional interface

  • Yes, defined a method which takes a mapper, which we can use and apply internally
public static ItemImageType extractOrCreateDefaultImage(
    @NonNull ItemType item,
    @NonNull Function<ItemType, String> defaultTitleFn,
    @NonNull Function<ItemType, String> defaultUrlFn) {
    // implementation
    // defaultTitleFn.apply(item)
    // defaultUrlFn.apply(item)
}

Parallel Streams

books.parallelStream()...findFirst();