Skip to content

Latest commit

 

History

History
410 lines (361 loc) · 13.7 KB

File metadata and controls

410 lines (361 loc) · 13.7 KB

Built-in Interfaces

Objective
Develop code that uses the built-in interfaces included in the java.util.function package, such as Function, Consumer, Supplier, UnaryOperator, Predicate, and Optional APIs, including the primitive and binary variations of the interfaces

Functional Interfaces

Java 8 has some Functional Interfaces already created. They will probably be enough for most scenarios where it is usual to use lambda expressions, so it should not be routine for you to create a new one.

It is critical to understand these examples to master the use of lambda expressions and to understand the next section on method references.

Supplier
  1. Supplier is a functional interface that takes no input parameters but returns a value. Its definition in JDK is as follows:

    java.util.function.Supplier<T>
    @FunctionalInterface
    public interface Supplier<T> {
        T get();
    }
  2. A possible implementation for a Supplier is a current date generator:

    src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_SupplierExample.java
    link:../../../src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_SupplierExample.java[role=include]
    console output
    2019-07-08

    The console output will print the current date this code was written.

    Note that the lambda expression is simplified, without {} or return braces. If you have questions about this, go back again to the section on lambda expressions.

  3. A Supplier can be used to provide a costly processing function to be called only if needed:

    src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_SupplierUseCase.java
    link:../../../src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_SupplierUseCase.java[role=include]
    console output
    Under age!
    Major age! Validation performed at 2019-07-09T00:21:35.488

    Note that in this case, the supplier only needed to be called at the second time, avoiding unnecessary execution of the lambda expression.

  4. There are Supplier interfaces for handling primitive types: BooleanSupplier, IntSupplier, LongSupplier and DoubleSupplier.

    src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_SupplierPrimitive.java
    link:../../../src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_SupplierPrimitive.java[role=include]

    The result in the console will be to print the randomly generated primitive int.

Consumer and BiConsumer
  1. Consumer is a functional interface that takes an input parameter, and returns no value. Its definition in JDK is as follows:

    java.util.function.Supplier<T>
    @FunctionalInterface
    public interface Consumer<T> {
        void accept(T t);
    }
  2. BiConsumer is a functional interface that takes two input parameters, and returns no value. Its definition in JDK is as follows:

    java.util.function.Consumer<T>
    @FunctionalInterface
    public interface BiConsumer<T, U> {
        void accept(T t, U u);
    }
  3. Possible implementations for Consumer or` BiConsumer` are functions that print information to the console:

    src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_ConsumerExample.java
    link:../../../src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_ConsumerExample.java[role=include]
    console output
    2019-07-08
    2019-07-08
    22:37:39.229
  4. There are Consumer interfaces to handle primitive types: DoubleConsumer, IntConsumer, LongConsumer, ObjDoubleConsumer, ObjIntConsumer and ObjLongConsumer.

    src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_ConsumerPrimitive.java
    link:../../../src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_ConsumerPrimitive.java[role=include]
Predicate and BiPredicate
  1. Predicate is a functional interface that takes an input parameter and returns a boolean value. Its definition in JDK is as follows:

    java.util.function.Predicate<T>
    @FunctionalInterface
    public interface Predicate<T> {
        boolean test(T t);
    }
  2. BiPredicate is a functional interface that takes two input parameters and returns a boolean value. Its definition in JDK is as follows:

    java.util.function.BiPredicate<T>
    @FunctionalInterface
    public interface BiPredicate<T, U> {
        boolean test(T t, U u);
    }
  3. Possible implementations for Predicate or BiPredicate are functions that check whether the input value is equal to the raffled value:

    src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_PredicateExample.java
    link:../../../src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_PredicateExample.java[role=include]

    The output on the console is random as it depends on the amount raffled. A possible value would be false and true.

  4. There are Predicate interfaces for handling primitive types: DoublePredicate, IntPredicate and LongPredicate.

    src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_PredicatePrimitive.java
    link:../../../src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_PredicatePrimitive.java[role=include]
Function and BiFunction
  1. Function is a functional interface that takes an input parameter and returns a value. Its definition in JDK is as follows:

    java.util.function.Function<T, R>
    @FunctionalInterface
    public interface Function<T, R> {
        R apply(T t);
    }
  2. BiFunction is a functional interface that takes two input parameters and returns a value. Its definition in JDK is as follows:

    java.util.function.BiFunction<T>
    @FunctionalInterface
    public interface BiFunction<T, U, R> {
        R apply(T t, U u);
    }
  3. Possible implementations for Function or BiFunction are functions that multiply the given values:

    src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_FunctionExample.java
    link:../../../src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_FunctionExample.java[role=include]
    console output
    7.5
    30.0
  4. There are several Function interfaces for handling primitive types: DoubleFunction, DoubleToIntFunction, DoubleToLongFunction, IntFunction, IntToDoubleFunction, IntToLongFunction, LongFunction, LongToDoubleFunction, LongToIntFunction, ToDoubleBiFunction, ToDoubleFunction, ToIntBiFunction, ToIntFunction, ToLongBiFunction, ToLongFunction.

    src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_FunctionPrimitive.java
    link:../../../src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_FunctionPrimitive.java[role=include]
    console output
    7.5
    30.0
UnaryOperator and BinaryOperator
  1. UnaryOperator is a functional interface that takes an input parameter and returns a value of the same type as the input. Its definition in JDK is as follows:

    java.util.function.Function<T, R>
    @FunctionalInterface
    public interface UnaryOperator<T> extends Function<T, T> {
    
    }

    Note that there is no declared abstract method as it only extends the existing Function interface.

  2. BinaryOperator is a functional interface that takes two input parameters of the same type, and returns a value of the same type as the inputs. Its definition in JDK is as follows:

    java.util.function.BiFunction<T>
    @FunctionalInterface
    public interface BinaryOperator<T> extends BiFunction<T,T,T> {
    
    }

    Note that there is no declared abstract method as it only extends the existing BiFunction interface.

  3. Possible implementations for UnaryOperator or BinaryOperator are functions that add a fixed number or add one number to another:

    src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_OperatorExample.java
    link:../../../src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_OperatorExample.java[role=include]
    console output
    9
    6
  4. There are Operator interfaces to handle primitive types: DoubleBinaryOperator, DoubleUnaryOperator, IntBinaryOperator, IntUnaryOperator, LongBinaryOperator, LongUnaryOperator.

    src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_OperatorPrimitive.java
    link:../../../src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_OperatorPrimitive.java[role=include]
    console output
    9
    6

Optional

Java 8 has a specific type to represent values that may not have been entered, which is the Optional class. Starting with Java 8, it is often a better option than returning or storing null, as its methods help in many situations.

  1. You can create an instance of Optional with value through the of method.

  2. You can create a worthless instance of Optional using the empty method.

  3. You can check if an instance of Optional has a value through the isPresent method.

  4. You can retrieve the value of an instance of Optional through the get method.

    src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_OptionalCreation.java
    link:../../../src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_OptionalCreation.java[role=include]
  5. It is not possible to call the of method by passing null as an argument. For this there is the ofNullable method.

    src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_OptionalNullable.java
    link:../../../src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_OptionalNullable.java[role=include]
    console output
    java.lang.NullPointerException
    	at java.util.Objects.requireNonNull(Objects.java:203)
    	at java.util.Optional.<init>(Optional.java:96)
    	at java.util.Optional.of(Optional.java:108)
    	at org.j6toj8.lambda.builtininterfaces.BuiltInInterfaces_OptionalNullable.main(BuiltInInterfaces_OptionalNullable.java:11)
    false
  6. With the ifPresent method you can execute a lambda expression only if Optional has value.

    src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_OptionalIfPresent.java
    link:../../../src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_OptionalIfPresent.java[role=include]
    console output
    With Value: value
  7. You can retrieve a default value if Optional is empty. The orElse method returns a value directly, and orElseGet returns via a lambda expression.

    src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_OptionalOrElse.java
    link:../../../src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_OptionalOrElse.java[role=include]
    console output
    default value
    default value
    value
    value
    Tip
    Note that this is a great case for remembering a benefit of lambda expressions. When using orElseGet the lambda expression is only executed if Optional is empty. In the case of the example, as it is only the return of a String, it makes no difference. However, if it were a heavier operation, you would only actually perform it if Optional was empty. If there was value, the lambda expression would not even be executed, avoiding the processing cost.
  8. You can also throw an exception if a value is not present in Optional using the orElseThrow method.

    src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_OptionalOrElseThrow.java
    link:../../../src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_OptionalOrElseThrow.java[role=include]
    console output
    value
    Exception in thread "main" java.lang.RuntimeException
    	at org.j6toj8.lambda.builtininterfaces.BuiltInInterfaces_OptionalOrElseThrow.lambda$main$1(BuiltInInterfaces_OptionalOrElseThrow.java:17)
    	at java.util.Optional.orElseThrow(Optional.java:290)
    	at org.j6toj8.lambda.builtininterfaces.BuiltInInterfaces_OptionalOrElseThrow.main(BuiltInInterfaces_OptionalOrElseThrow.java:17)
  9. An exception will be thrown when calling the get method on an empty Optional.

    src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_OptionalGetEmpty.java
    link:../../../src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_OptionalGetEmpty.java[role=include]
    console output
    value
    Exception in thread "main" java.util.NoSuchElementException: No value present
    	at java.util.Optional.get(Optional.java:135)
    	at org.j6toj8.lambda.builtininterfaces.BuiltInInterfaces_OptionalGetEmpty.main(BuiltInInterfaces_OptionalGetEmpty.java:13)
  10. There are some classes for dealing with optional value of primitive variables, as they cannot be used with generics: OptionalInt, OptionalDouble, OptionalLong.

    src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_OptionalPrimitive.java
    link:../../../src/org/j6toj8/lambda/builtininterfaces/BuiltInInterfaces_OptionalPrimitive.java[role=include]
    console output
    5
References