New features of JDK 1.8 -- functional interface

In the last article, we introduced the following new features of JDK 1.8.

1.Lambda expression

2. Method reference

3. Functional interface

4. Default method

5.Stream

6.Optional

7. Nansharm JavaScript engine

8. New date time API

9.Base64

Before that, I learned the first two Lambda expressions, method references, and this article is about functional interfaces.

The so-called functional interface can only define one abstract method, and other methods can be qualified by default or static key.

Let's verify it with an example.

Define a functional interface, then define an abstract method called testA, and then define an abstract method called testB.

  

The @ FunctionalInterface annotation will prompt the following error. (multiple abstract methods not covered are found in the interface)

Then I'll try changing testB to a non abstract method.

It was found that there was another mistake after the correction. Let's keep looking at the new mistakes.

Next we add the default keyword to the method

There is no error message at this time. In addition to the abstract methods, there can be default non static methods in the functional interface.

Next, I'll change the default to static to see if there can be static methods.

No problem found at this time. That means there can be static methods in functional interfaces.

Because the Object class is the parent class of all classes, all methods that can be overridden in the interface can be defined in the interface. such as

toString, equals method.

After learning about functional interfaces, let's talk about the four built-in functional interfaces of API.  

Mainly on the following

1. Consumer -- consumer interface

2. Supplier -- supply interface

3. Function -- function interface

4. Predicate -- assertion interface

Let's take a look at the API source code in turn, and write examples to understand the usage methods and characteristics of each type of interface.

1. Consumer (used when there is incoming and no outgoing)

The official source code is as follows. In order to be convenient and concise, the comments at the beginning are removed, and only the comments of methods are reserved.

 1 package java.util.function;
 2 
 3 import java.util.Objects;
 4 
 5 @FunctionalInterface
 6 public interface Consumer<T> {
 7 
 8     /**
 9      * Performs this operation on the given argument.
10      *
11      * @param t the input argument
12      */
13     void accept(T t);
14 
15     /**
16      * Returns a composed {@code Consumer} that performs, in sequence, this
17      * operation followed by the {@code after} operation. If performing either
18      * operation throws an exception, it is relayed to the caller of the
19      * composed operation.  If performing this operation throws an exception,
20      * the {@code after} operation will not be performed.
21      *
22      * @param after the operation to perform after this operation
23      * @return a composed {@code Consumer} that performs in sequence this
24      * operation followed by the {@code after} operation
25      * @throws NullPointerException if {@code after} is null
26      */
27     default Consumer<T> andThen(Consumer<? super T> after) {
28         Objects.requireNonNull(after);
29         return (T t) -> { accept(t); after.accept(t); };
30     }
31 }

Look directly at the accept abstract method. It receives a t of generic type T. the return value type is void. We call it a consumer interface. The characteristic is that there is no return.

Let's take a look at the example directly

 1 public class InfixFunctionTest {
 2     //1.Consumer interface
 3     @Test
 4     public void test1(){
 5         //Print the incoming string
 6         Consumer<String> con = x -> System.out.println(x);//Implementation of definition function
 7         con.accept("Hello Consumer!");//Receive parameters
 8     }
 9 
10 }

results of enforcement

com.dream.test.JDK8speciality.InfixFunctionTest,test1
Hello Consumer!

Process finished with exit code 0

We just need to pass an x in the parameter list of Lambda expression, and then the implementation is: get a print statement without return type.

2. Supplier (no incoming, use when there is outgoing)

Official source code

 1 package java.util.function;
 2 
 3 /**
 4  * Represents a supplier of results.
 5  *
 6  * <p>There is no requirement that a new or distinct result be returned each
 7  * time the supplier is invoked.
 8  *
 9  * <p>This is a <a href="package-summary.html">functional interface</a>
10  * whose functional method is {@link #get()}.
11  *
12  * @param <T> the type of results supplied by this supplier
13  *
14  * @since 1.8
15  */
16 @FunctionalInterface
17 public interface Supplier<T> {
18 
19     /**
20      * Gets a result.
21      *
22      * @return a result
23      */
24     T get();
25 }

The get method returns a T, which is called the supplied interface, without passing in parameters. It is characterized by no effort but return.

example

 1 public class InfixFunctionTest {
 2 
 3     //2.Supply type interface
 4     @Test
 5     public void test2(){
 6         Supplier<String> su = () -> new String();
 7         String str = su.get();
 8         System.out.println("Value of supply type interface:" + str);
 9     }
10 
11 }

results of enforcement

com.dream.test.JDK8speciality.InfixFunctionTest,test2
 Value of supply type interface:

Process finished with exit code 0

We passed in parameters in Lambda expression with () to represent no parameters passed in, and then returned an object of String type.

3.Function (with incoming parameters, used when outgoing)

Official source code

 1 package java.util.function;
 2 
 3 import java.util.Objects;
 4 
 5 /**
 6  * Represents a function that accepts one argument and produces a result.
 7  *
 8  * <p>This is a <a href="package-summary.html">functional interface</a>
 9  * whose functional method is {@link #apply(Object)}.
10  *
11  * @param <T> the type of the input to the function
12  * @param <R> the type of the result of the function
13  *
14  * @since 1.8
15  */
16 @FunctionalInterface
17 public interface Function<T, R> {
18 
19     /**
20      * Applies this function to the given argument.
21      *
22      * @param t the function argument
23      * @return the function result
24      */
25     R apply(T t);
26 
27     /**
28      * Returns a composed function that first applies the {@code before}
29      * function to its input, and then applies this function to the result.
30      * If evaluation of either function throws an exception, it is relayed to
31      * the caller of the composed function.
32      *
33      * @param <V> the type of input to the {@code before} function, and to the
34      *           composed function
35      * @param before the function to apply before this function is applied
36      * @return a composed function that first applies the {@code before}
37      * function and then applies this function
38      * @throws NullPointerException if before is null
39      *
40      * @see #andThen(Function)
41      */
42     default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
43         Objects.requireNonNull(before);
44         return (V v) -> apply(before.apply(v));
45     }
46 
47     /**
48      * Returns a composed function that first applies this function to
49      * its input, and then applies the {@code after} function to the result.
50      * If evaluation of either function throws an exception, it is relayed to
51      * the caller of the composed function.
52      *
53      * @param <V> the type of output of the {@code after} function, and of the
54      *           composed function
55      * @param after the function to apply after this function is applied
56      * @return a composed function that first applies this function and then
57      * applies the {@code after} function
58      * @throws NullPointerException if after is null
59      *
60      * @see #compose(Function)
61      */
62     default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
63         Objects.requireNonNull(after);
64         return (T t) -> after.apply(apply(t));
65     }
66 
67     /**
68      * Returns a function that always returns its input argument.
69      *
70      * @param <T> the type of the input and output objects to the function
71      * @return a function that always returns its input argument
72      */
73     static <T> Function<T, T> identity() {
74         return t -> t;
75     }
76 }

The Function interface provides an abstract method, two default methods and a static method. Here I will explain only the most commonly used abstract methods.

The apply method takes a t of type T and returns a value of type R. We call it a functional interface. The characteristic is that you come and I go. (as the saying goes, it's good to come without being rude! Hahaha!)

example

 1 public class InfixFunctionTest {
 2  
 3     //3.Functional interface
 4     @Test
 5     public void test3(){
 6         Function<String,Camera> fun = (x) -> new Camera(x);//The implementation of Function abstract Function.
 7         Camera camera = fun.apply("Sony-A7R3");//Receive incoming parameters
 8         System.out.println("cameraName: " + camera.getCameraName() + " price:" + camera.getPrice());
 9     }
10 
11 }

Camera class

 1 //Camera class
 2 class Camera{
 3     //Camera name
 4     private String cameraName;
 5     //Camera price
 6     private Integer price;
 7 
 8     //Parameterless constructor
 9     public Camera(){
10 
11     }
12 
13     //Parametric constructor
14     public Camera(String cameraName){
15         this.cameraName = cameraName;
16     }
17 
18     //Parametric constructor
19     public Camera(String cameraName,Integer price){
20         this.cameraName = cameraName;
21         this.price = price;
22     }
23 
24     public String getCameraName() {
25         return cameraName;
26     }
27 
28     public void setCameraName(String cameraName) {
29         this.cameraName = cameraName;
30     }
31 
32     public Integer getPrice() {
33         return price;
34     }
35 
36     public void setPrice(Integer price) {
37         this.price = price;
38     }
39 }

results of enforcement

com.dream.test.JDK8speciality.InfixFunctionTest,test3
cameraName: Sony-A7R3 price:null

Process finished with exit code 0

A parameter x is passed in the Lam expression, and then x is used as the constructor's parameter to return a Camera object.

4. Predict (pass in a parameter and return a result of boolean type)

Official website source code

 1 package java.util.function;
 2 
 3 import java.util.Objects;
 4 
 5 /**
 6  * Represents a predicate (boolean-valued function) of one argument.
 7  *
 8  * <p>This is a <a href="package-summary.html">functional interface</a>
 9  * whose functional method is {@link #test(Object)}.
10  *
11  * @param <T> the type of the input to the predicate
12  *
13  * @since 1.8
14  */
15 @FunctionalInterface
16 public interface Predicate<T> {
17 
18     /**
19      * Evaluates this predicate on the given argument.
20      *
21      * @param t the input argument
22      * @return {@code true} if the input argument matches the predicate,
23      * otherwise {@code false}
24      */
25     boolean test(T t);
26 
27     /**
28      * Returns a composed predicate that represents a short-circuiting logical
29      * AND of this predicate and another.  When evaluating the composed
30      * predicate, if this predicate is {@code false}, then the {@code other}
31      * predicate is not evaluated.
32      *
33      * <p>Any exceptions thrown during evaluation of either predicate are relayed
34      * to the caller; if evaluation of this predicate throws an exception, the
35      * {@code other} predicate will not be evaluated.
36      *
37      * @param other a predicate that will be logically-ANDed with this
38      *              predicate
39      * @return a composed predicate that represents the short-circuiting logical
40      * AND of this predicate and the {@code other} predicate
41      * @throws NullPointerException if other is null
42      */
43     default Predicate<T> and(Predicate<? super T> other) {
44         Objects.requireNonNull(other);
45         return (t) -> test(t) && other.test(t);
46     }
47 
48     /**
49      * Returns a predicate that represents the logical negation of this
50      * predicate.
51      *
52      * @return a predicate that represents the logical negation of this
53      * predicate
54      */
55     default Predicate<T> negate() {
56         return (t) -> !test(t);
57     }
58 
59     /**
60      * Returns a composed predicate that represents a short-circuiting logical
61      * OR of this predicate and another.  When evaluating the composed
62      * predicate, if this predicate is {@code true}, then the {@code other}
63      * predicate is not evaluated.
64      *
65      * <p>Any exceptions thrown during evaluation of either predicate are relayed
66      * to the caller; if evaluation of this predicate throws an exception, the
67      * {@code other} predicate will not be evaluated.
68      *
69      * @param other a predicate that will be logically-ORed with this
70      *              predicate
71      * @return a composed predicate that represents the short-circuiting logical
72      * OR of this predicate and the {@code other} predicate
73      * @throws NullPointerException if other is null
74      */
75     default Predicate<T> or(Predicate<? super T> other) {
76         Objects.requireNonNull(other);
77         return (t) -> test(t) || other.test(t);
78     }
79 
80     /**
81      * Returns a predicate that tests if two arguments are equal according
82      * to {@link Objects#equals(Object, Object)}.
83      *
84      * @param <T> the type of arguments to the predicate
85      * @param targetRef the object reference with which to compare for equality,
86      *               which may be {@code null}
87      * @return a predicate that tests if two arguments are equal according
88      * to {@link Objects#equals(Object, Object)}
89      */
90     static <T> Predicate<T> isEqual(Object targetRef) {
91         return (null == targetRef)
92                 ? Objects::isNull
93                 : object -> targetRef.equals(object);
94     }
95 }

The Predicate interface provides an abstract method, three default methods, and a static method. Here is an example of an abstract method.

Since a boolean type value is returned, we call it an assertion type. The feature is to make a request and wait for instructions (do or not, ha ha).

 1 public class InfixFunctionTest {
 2 
 3     //4.Assertive interface
 4     @Test
 5     public void test4(){
 6         Predicate<String> pre = x -> x == null;
 7         Boolean b =pre.test(null);
 8         System.out.println("Assertive test results:" + b);
 9     }
10 
11 }

results of enforcement

com.dream.test.JDK8speciality.InfixFunctionTest,test4
//Assertive test results:true

Process finished with exit code 0

Lambda expression passes in a parameter x to judge whether x is null or not.

The package and import package information of the header are omitted in the above examples. The package information is as follows.

1 package com.dream.test.JDK8speciality;
2 
3 import org.junit.Test;
4 
5 import java.util.function.Consumer;
6 import java.util.function.Function;
7 import java.util.function.Predicate;
8 import java.util.function.Supplier;

 

java.util.function In addition to the above basic functional interfaces, there are many more under the package. The others are all the basic derivatives. If these are understood, the rest will not be difficult to understand. If you are interested, you can do your own research.

The above is the study of function. If you find something wrong or bad, please correct it. Thank you very much.

Last article

New features of JDK 1.8 (2) -- method reference

Tags: Java Lambda JDK Javascript

Posted on Fri, 22 May 2020 05:43:03 -0700 by False