Special topic on new features of JDK8-03 functional interface

Posted by sprinkles on Sun, 19 Dec 2021 09:26:03 +0100

1. Origin of functional interface

We know that the premise of using Lambda expression is to have functional interface, and Lambda expression does not care about interface name and abstract method name. Only the parameter list and return value type of the abstract method are concerned. Therefore, in order to make it easier for us to use Lambda expressions, a large number of commonly used functional interfaces are provided in JDK

public class Demo01Fun {

    public static void main(String[] args) {
        fun1((arr)->{
            int sum = 0 ;
            for (int i : arr) {
                sum += i;
            }
            return sum;
        });
    }

    public static void fun1(Operator operator){
        int[] arr = {1,2,3,4};
        int sum = operator.getSum(arr);
        System.out.println("sum = " + sum);
    }
}

/**
 * Functional interface
 */
@FunctionalInterface
interface Operator{

    int getSum(int[] arr);
}

2. Introduction to functional interface

The JDK provides us with functional interfaces, mainly in Java util. Function package.

2.1.Supplier

For interfaces with no parameters and return values, you need to provide a return data type for Lambda expressions.

@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}

use:

/**
 * Supplier Use of functional interfaces
 */
public class SupplierTest {

    public static void main(String[] args) {
        fun1(()->{
            int arr[] = {22,33,55,66,44,99,10};
            // Calculate the maximum value in the array
            Arrays.sort(arr);
            return arr[arr.length-1];
        });
    }

    private static void fun1(Supplier<Integer> supplier){
        // get() is an abstract method with no parameters and a return value
        Integer max = supplier.get();
        System.out.println("max = " + max);

    }
}

2.2.Consumer

The Supplier interface described above is used to produce data, while the Consumer interface is used to consume data. When using, you need to specify a generic type to define the parameter type

@FunctionalInterface
public interface Consumer<T> {

    /**
     * Performs this operation on the given argument.
     *
     * @param t the input argument
     */
    void accept(T t);
}

Use: uniformly convert the input data to lowercase output

public class ConsumerTest {

    public static void main(String[] args) {
        test(msg -> {
            System.out.println(msg + "-> Convert to lowercase:" + msg.toLowerCase());
        });
    }

    public static void test(Consumer<String> consumer){
        consumer.accept("Hello World");
    }
}

Default method: andThen

If all the parameters and return values of a method are of Consumer type, the effect can be achieved. When consuming a data, first do an operation, and then do an operation to realize the combination. This method is the default method and then method in the Consumer interface

 default Consumer<T> andThen(Consumer<? super T> after) {
     Objects.requireNonNull(after);
     return (T t) -> { accept(t); after.accept(t); };
 }

Specific operation

public class ConsumerAndThenTest {

    public static void main(String[] args) {
        test2(msg1->{
            System.out.println(msg1 + "-> Convert to lowercase:" + msg1.toLowerCase());
        },msg2->{
            System.out.println(msg2 + "-> Convert to uppercase:" + msg2.toUpperCase());
        });
    }


    public static void test2(Consumer<String> c1,Consumer<String> c2){
        String str = "Hello World";
        //c1.accept(str); //  Turn lowercase
        //c2.accept(str); //  Capitalize
        //c1.andThen(c2).accept(str);
        c2.andThen(c1).accept(str);
    }
}

2.3.Function

The Function interface is an interface with parameters and return values. The Function interface obtains data of another type from data of one type. The former is called a precondition and the latter is called a postcondition. There are parameters and return values.

@FunctionalInterface
public interface Function<T, R> {

    /**
     * Applies this function to the given argument.
     *
     * @param t the function argument
     * @return the function result
     */
    R apply(T t);
}

Use: pass into a string and return a number

public class FunctionTest {

    public static void main(String[] args) {
        test(msg ->{
            return Integer.parseInt(msg);
        });
    }

    public static void test(Function<String,Integer> function){
        Integer apply = function.apply("666");
        System.out.println("apply = " + apply);
    }
}

Default method: andThen, which is also used for combination operation

default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
    Objects.requireNonNull(after);
    return (T t) -> after.apply(apply(t));
}
public class FunctionAndThenTest {

    public static void main(String[] args) {
        test(msg ->{
            return Integer.parseInt(msg);
        },msg2->{
            return msg2 * 10;
        });
    }

    public static void test(Function<String,Integer> f1,Function<Integer,Integer> f2){
        /*Integer i1 = f1.apply("666");
        Integer i2 = f2.apply(i1);*/
        Integer i2 = f1.andThen(f2).apply("666");
        System.out.println("i2:" + i2);

    }
}

2.4.Predicate

Interface with parameter and return value of Boolean

@FunctionalInterface
public interface Predicate<T> {

    /**
     * Evaluates this predicate on the given argument.
     *
     * @param t the input argument
     * @return {@code true} if the input argument matches the predicate,
     * otherwise {@code false}
     */
    boolean test(T t);
}

use:

public class PredicateTest {

    public static void main(String[] args) {
        test(msg -> {
            return msg.length() > 3;
        },"HelloWorld");
    }

    private static void test(Predicate<String> predicate,String msg){
        boolean b = predicate.test(msg);
        System.out.println("b:" + b);
    }
}

The default method in predict provides the logical relationship operation and or close isequals method

public class PredicateDefaultTest {

    public static void main(String[] args) {
        test(msg1 -> {
            return msg1.contains("H");
        },msg2 -> {
            return msg2.contains("W");
        });
    }

    private static void test(Predicate<String> p1,Predicate<String> p2){
        /*boolean b1 = predicate.test(msg);
        boolean b2 = predicate.test("Hello");*/
        // b1 contains h and B2 contains W
        // p1 contains H and p2 contains W
        boolean bb1 = p1.and(p2).test("Hello");
        // p1 contains H or p2 contains W
        boolean bb2 = p1.or(p2).test("Hello");
        // p1 does not contain H
        boolean bb3 = p1.negate().test("Hello");
        System.out.println(bb1); // FALSE
        System.out.println(bb2); // TRUE
        System.out.println(bb3); // FALSE
    }
}

~Well, that's all for the functional interface

Topics: Java Scala