Example details the Java8 functional interface

  • 2020-12-05 17:12:56
  • OfStack

Let's move on to the Java8 functional programming model


public class Test1 {
  public static void main(String[] args) {
    List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
    list.forEach(new Consumer<Integer>() {
      @Override
      public void accept(Integer integer) {
        System.out.println(integer);
      }
    });
  }
}

This program is simple. It initializes a collection of type Integer and outputs each element to the console. Here we notice the forEach method, which is the new default method added to Java8.


public interface Iterable<T> {
  .
  . omit 
  .
  default void forEach(Consumer<? super T> action) {
    Objects.requireNonNull(action);
    for (T t : this) {
      action.accept(t);
    }
  }
}

It is declared in the Iterable interface and is decorated with the keyword default. Any subtype of this interface inherits the implementation of the forEach method, so the List interface inherits the default method because it is an indirect subtype of Iterable. Java8 is a clever way to extend the functionality of the interface while being compatible with older versions.

Next, the implementation of forEach is analyzed. First, one parameter of Consumer type action is received for non-null judgment, and then all the current elements are processed by accept method of action. So what the hell is Consumer, look at the source code


@FunctionalInterface
public interface Consumer<T> {

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

1 interface, with and only 1 abstract method, decorated with @FunctionalInterface, typical functional interface.

ok. Now we know that the argument of type Consumer received by forEach is a functional interface, in which the only abstract method of accept receives one argument without returning a value. So as we learned in the last article, one way to create an instance of a functional interface type is to use the Lambda expression, so you can modify the top program 1


public class Test1 {
  public static void main(String[] args) {
    List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
    //Lambda expression   receive 1 A parameter   No return value 
    list.forEach(item -> System.out.println(item));
  }
}

The lambda expression item - > System.out.println (item) receives 1 parameter without return value, complies with accept method signature requirement, and is compiled.
That is, if an lambda expression is used to create an instance of a functional interface, the input and return of the lambda expression must conform to the method signature of the only abstract method in the functional interface.

And then I'm going to modify the program


public class Test1 {
  public static void main(String[] args) {
    List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
    // Method references 
    list.forEach(System.out::println);
  }
}

There were two colons after out, which was a mess anyway... This is the second way to create a functional interface instance: a method reference. The syntax for a method reference is the object :: method name

Also, using a method reference to create a functional interface instance must follow the definition of a method signature, as shown here in the println method source code


public void println(Object x) {
  String s = String.valueOf(x);
  synchronized (this) {
    print(s);
    newLine();
  }
}

Accepts 1 argument, does not return value, compile ok.

Finally, let's look at the last way to create a functional interface, and the third way: construct a method reference, and continue modifying the program


public class Test1 {
  public static void main(String[] args) {
    List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
    // Constructor reference 
    list.forEach(Test1::new);
  }
  
  Test1(Integer i){
    System.out.println(i);
  }
}

The syntax for the constructor reference is: class name ::new

We add a new constructor to Test1, which takes 1 parameter, returns no value, and is compiled. (To show usage of constructor references only)

In combination with the previous article, we can summarize the following three ways to create functional interface types:

1. lambda expression

2. Method references

3. Constructor reference

Note: Either way, you must conform to the abstract method's method signature


Related articles: