This article is participating in “Java Theme Month – Java Debug Notes Event”, see < Event link > for more details.

The previous article “Lambda expressions, so you can’t put it down”, just a simple talk about the syntax and use of Lambda expressions, so that you have a good impression of it, and how Lambda expressions are implemented and defined, you may not be very clear. This article will cover functional interfaces in detail so you can feel confident when using new JDK features.

1. Functional interfaces

Functional Interface, an Interface that has one and only abstract method, but can have multiple non-abstract methods.

Applies to the interface used by Lambda expressions. For example:

new Thread(() -> System.out.println(Thread.currentThread().getName())).start();
Copy the code

Lambda expressions replace new Runnable(), where the Runable interface is a FunctionalInterface, most intuitively using the @functionalinterface annotation, and using an abstract method (there is one and only one) as follows:

package java.lang; /** * The <code>Runnable</code> interface should be implemented by any * class whose instances are intended to be executed by a thread. The * class must define a method of no arguments called <code>run</code>. * <p> * This interface is designed to provide a common protocol for objects that * wish to execute code while they are active. For example, * <code>Runnable</code> is implemented by class <code>Thread</code>. * Being active simply means that a thread has been started and has not * yet been stopped. * <p> * In addition, <code>Runnable</code> provides the means for a class to be * active while not subclassing <code>Thread</code>. A class that implements * <code>Runnable</code> can run without subclassing <code>Thread</code> * by instantiating a <code>Thread</code> instance and passing itself in * as the target. In most cases, the <code>Runnable</code> interface should * be used if you are only planning to override the <code>run()</code> * method and no other <code>Thread</code> methods. * This is important because classes should not be subclassed * unless the programmer intends on modifying or enhancing the fundamental * behavior of the class. * * @author Arthur van Hoff * @ see Java. Lang. @ see Java Thread *. Util. Concurrent. Callable * @ since JDK1.0 * / @ FunctionalInterface public interface Runnable { /** * When an object implementing interface <code>Runnable</code> is used * to create a thread, starting the thread causes the object's * <code>run</code> method to be called in that separately executing * thread. * <p> * The general contract of the method <code>run</code> is that it may * take any action whatsoever. * * @see java.lang.Thread#run() */ public abstract void run(); }Copy the code

1. The format

Interface Interface name {

Public abstract Return value type method name (optional argument list);

}

Note:public abstractCan be omitted (because the default is modified topublic abstract)

Such as:

public interface MyFunctionalInterface {
    public abstract void method();
}
Copy the code

2. Comments @ FunctionalInterface

@functionalinterface is a new annotation in JDK1.8 that specifically refers to functional interfaces and is used to define an interface.

Similar to the @override annotation, the @functionalinterface annotation can be used to check whether an interface is a FunctionalInterface. If it is a functional interface, the compilation succeeds; otherwise, the compilation fails (the interface has no abstract methods or more than one abstract method).

package com.xcbeyond.study.jdk8.functional; /** ** @date: 2020/5/17 0017 0:26 */ @FunctionalInterface public interface MyFunctionalInterface { public abstract void method(); Public abstract void method1(); }Copy the code

Example 3.

Functional interface:

package com.xcbeyond.study.jdk8.functional; /** ** @date: 2020/5/17 0017 0:26 */ @FunctionalInterface public interface MyFunctionalInterface { public abstract void method(); Public abstract void method1(); }Copy the code

Testing:

package com.xcbeyond.study.jdk8.functional; /** * test function interface * @auther: xcbeyond * @date: 2020/5/17 0:47 * 0017 / public class MyFunctionalInterfaceTest {public static void main (String [] args) {/ / call the show method, The argument has a functional interface MyFunctionalInterface, so you can use Lambda expressions to implement the interface show(" Hello xcbeyond!"). , msg -> System.out.printf(msg)); } /** * define a method, MyFunctionalInterface * @param MyFunctionalInterface */ public static void show(String message, MyFunctionalInterface myFunctionalInterface) { myFunctionalInterface.method(message); }}Copy the code

Functional interface, use is not more flexible, can be called in the specific implementation of the interface.

A functional interface that can nicely support Lambda expressions.

Two, commonly used functional interface

Prior to JDK1.8 there were a number of functional interfaces, the most familiar being the java.lang.Runnable interface.

Functional interfaces available before JDK 1.8:

  • java.lang.Runnable
  • java.util.concurrent.Callable
  • java.security.PrivilegedAction
  • java.util.Comparator
  • java.io.FileFilter
  • java.nio.file.PathMatcher
  • java.lang.reflect.InvocationHandler
  • java.beans.PropertyChangeListener
  • java.awt.event.ActionListener
  • javax.swing.event.ChangeListener

In JDK1.8, a number of functional interfaces are added under the java.util. Function package to support Java functional programming, thus enriching the use of Lambda expressions.

Here are four core functional interfaces:

  • java.util.function.Consumer: Consumer interface
  • java.util.function.Supplier: Supply interface
  • java.util.function.Predicate: Stereotyped interface
  • java.util.function.Function: functional interface

1. Consumer interface

Java. Util. The function. The Consumer interface, is a Consumer interface, consumption is determined by the generic data type.

package java.util.function; import java.util.Objects; /** * Represents an operation that accepts a single input argument and returns no * result. Unlike most other functional  interfaces, {@code Consumer} is expected * to operate via side-effects. * * <p>This is a <a href="package-summary.html">functional interface</a> * whose functional method is {@link #accept(Object)}. * * @param <T> the type of the input to the Operation ** @since 1.8 */ @functionalInterface Public Interface Consumer<T> {/** * Performs this operation on the given argument. * * @param t the input argument */ void accept(T t); /** * Returns a composed {@code Consumer} that performs, in sequence, this * operation followed by the {@code after} operation. If performing either * operation throws an exception, it is relayed to the caller of the * composed operation. If performing this operation throws an exception, * the {@code after} operation will not be performed. * * @param after the operation to perform after this operation * @return a composed {@code Consumer} that performs in sequence this * operation followed by the {@code after} operation *  @throws NullPointerException if {@code after} is null */ default Consumer<T> andThen(Consumer<? super T> after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; }}Copy the code

(1) Abstract method: Accept

The abstract method void Accept (T T) in the Consumer interface consumes data for a specified generic T.

Examples are as follows:

Void accept(T T) */ @test public void acceptMethodTest() {acceptMethod("xcbeyond", message -> { String Reverse = new StringBuffer(message).reverse().toString(); System.out.printf(reverse); }); } /** * define a method, * @param message * @param consumer */ public void acceptMethod(String message, Consumer<String> consumer) { consumer.accept(message); }Copy the code

(2) Method: andThen

The andThen method can be used to wire together multiple Consumer interfaces for data consumption.

/** * Returns a composed {@code Consumer} that performs, in sequence, this * operation followed by the {@code after} operation. If performing either * operation throws an exception, it is relayed to the caller of the * composed operation. If performing this operation throws an exception, * the {@code after} operation will not be performed. * * @param after the operation to perform after this operation * @return a composed {@code Consumer} that performs in sequence this * operation followed by the {@code after} operation *  @throws NullPointerException if {@code after} is null */ default Consumer<T> andThen(Consumer<? super T> after) { Objects.requireNonNull(after); return (T t) -> { accept(t); after.accept(t); }; }Copy the code

Examples are as follows:

/** * test Consumer<T> andThen(Consumer<? Super T> after)  * XCBEYOND * xcbeyond */ @Test public void andThenMethodTest() { andThenMethod("XCbeyond", T -> {// convert to size output system.out.println (t.toupperCase ()); }, t -> {// Convert to lowercase system.out.println (t.tolowerCase ()); }); } /** * define a method to connect two Consumer interfaces together, Consumer1 * @param Consumer2 */ public void andThenMethod(String message, Consumer<String> consumer1, Consumer<String> consumer2) { consumer1.andThen(consumer2).accept(message); }Copy the code

2. : Supplier interface

Java. Util. Function: Supplier interface, is a GongGeiXing interface, i.e., the production interface. Contains only one parameterless method: T get(), which fetches data of the type specified by a generic parameter.

package java.util.function;

/**
 * Represents a supplier of results.
 *
 * <p>There is no requirement that a new or distinct result be returned each
 * time the supplier is invoked.
 *
 * <p>This is a <a href="package-summary.html">functional interface</a>
 * whose functional method is {@link #get()}.
 *
 * @param <T> the type of results supplied by this supplier
 *
 * @since 1.8
 */
@FunctionalInterface
public interface Supplier<T> {

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

Examples are as follows:

@Test public void test() { String str = getMethod(() -> "hello world!" ); System.out.println(str); } public String getMethod(Supplier<String> supplier) { return supplier.get(); }Copy the code

3. The Predicate interface

Java. Util. The function. The Predicate interface, is a broken finalize the design interface, is used to specify the type of data to judgment, a judgment result is obtained (the value of the Boolean type).

package java.util.function; import java.util.Objects; /** * Represents a predicate (boolean-valued function) of one argument. * * <p>This is a <a href="package-summary.html">functional interface</a> * whose functional method is {@link #test(Object)}. * * @param <T> The type of the input to the predicate ** @since 1.8 */ @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); /** * Returns a composed predicate that represents a short-circuiting logical * AND of this predicate and another. When evaluating the composed * predicate, if this predicate is {@code false}, then the {@code other} * predicate is not evaluated. * * <p>Any exceptions thrown during evaluation of either predicate are relayed * to the caller; if evaluation of this predicate throws an exception, the * {@code other} predicate will not be evaluated. * * @param other a predicate that will be logically-ANDed with this  * predicate * @return a composed predicate that represents the short-circuiting logical * AND of this predicate and the  {@code other} predicate * @throws NullPointerException if other is null */ default Predicate<T> and(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) && other.test(t); } /** * Returns a predicate that represents the logical negation of this * predicate. * * @return a predicate that represents the logical negation of this * predicate */ default Predicate<T> negate() { return (t) -> ! test(t); } /** * Returns a composed predicate that represents a short-circuiting logical * OR of this predicate and another. When  evaluating the composed * predicate, if this predicate is {@code true}, then the {@code other} * predicate is not evaluated. * * <p>Any exceptions thrown during evaluation of either predicate are relayed * to the caller; if evaluation of this predicate throws an exception, the * {@code other} predicate will not be evaluated. * * @param other a predicate that will be logically-ORed with this * predicate * @return a composed predicate that represents the short-circuiting logical * OR of this predicate and the {@code other} predicate * @throws NullPointerException if other is null */ default Predicate<T> or(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) || other.test(t); } /** * Returns a predicate that tests if two arguments are equal according * to {@link Objects#equals(Object, Object)}. * * @param <T> the type of arguments to the predicate * @param targetRef the object reference with which to compare for equality, * which may be {@code null} * @return a predicate that tests if two arguments are equal according * to {@link Objects#equals(Object, Object)} */ static <T> Predicate<T> isEqual(Object targetRef) { return (null == targetRef) ? Objects::isNull : object -> targetRef.equals(object); }}Copy the code

(1) Abstract method: test

Boolean test(T T); Boolean test(T 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);
Copy the code

Examples are as follows:

/** * test Boolean (T T); */ @Test public void testMethodTest() { String str = "xcbey0nd"; boolean result = testMethod(str, s -> s.equals("xcbeyond")); System.out.println(result); } /** * defines a method for determining strings. * @param str * @param predicate * @return */ public boolean testMethod(String str, Predicate predicate) { return predicate.test(str); }Copy the code

(2)

Method to Predicate the < T > and Predicate (
other), used to make the two Predicate logical and “judge”.

/** * Returns a composed predicate that represents a short-circuiting logical * AND of this predicate and another. When evaluating the composed * predicate, if this predicate is {@code false}, then the {@code other} * predicate is not evaluated. * * <p>Any exceptions thrown during evaluation of either predicate are relayed * to the caller; if evaluation of this predicate throws an exception, the * {@code other} predicate will not be evaluated. * * @param other a predicate that will be logically-ANDed with this  * predicate * @return a composed predicate that represents the short-circuiting logical * AND of this predicate and the  {@code other} predicate * @throws NullPointerException if other is null */ default Predicate<T> and(Predicate<? super T> other) { Objects.requireNonNull(other); return (t) -> test(t) && other.test(t); }Copy the code

(3) Method: negate

The Predicate

negate() method is used for Predicate.

/** * Returns a predicate that represents the logical negation of this * predicate. * * @return a predicate that represents the logical negation of this * predicate */ default Predicate<T> negate() { return (t) -> ! test(t); }Copy the code

(4) Method: or

Method to Predicate the < T > or (Predicate
other), for the logic of both Predicate “or” judgment.

/**
 * Returns a composed predicate that represents a short-circuiting logical
 * OR of this predicate and another.  When evaluating the composed
 * predicate, if this predicate is {@code true}, then the {@code other}
 * predicate is not evaluated.
 *
 * <p>Any exceptions thrown during evaluation of either predicate are relayed
 * to the caller; if evaluation of this predicate throws an exception, the
 * {@code other} predicate will not be evaluated.
 *
 * @param other a predicate that will be logically-ORed with this
 *              predicate
 * @return a composed predicate that represents the short-circuiting logical
 * OR of this predicate and the {@code other} predicate
 * @throws NullPointerException if other is null
 */
default Predicate<T> or(Predicate<? super T> other) {
    Objects.requireNonNull(other);
    return (t) -> test(t) || other.test(t);
}
Copy the code

4. The Function interface

Java. Util. The function. The function interface, is a functional interface, used to according to a type of data to get a different type of data.

package java.util.function; import java.util.Objects; /** * Represents a function that accepts one argument and produces a result. * * <p>This is a <a href="package-summary.html">functional interface</a> * whose functional method is {@link #apply(Object)}. * * @param <T> The type of the input to the function * @param <R> the type of the result of the function * * @since 1.8 */ @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); /** * Returns a composed function that first applies the {@code before} * function to its input, and then applies this function to the result. * If evaluation of either function throws an exception, it is relayed to * the caller of the composed function. * * @param <V> the type of input to the {@code before} function,  and to the * composed function * @param before the function to apply before this function is applied * @return a composed function that first applies the {@code before} * function and then applies this function * @throws NullPointerException if before is null * * @see #andThen(Function) */ default <V> Function<V, R> compose(Function<? super V, ? extends T> before) { Objects.requireNonNull(before); return (V v) -> apply(before.apply(v)); } /** * Returns a composed function that first applies this function to * its input, and then applies the {@code after} function to the result. * If evaluation of either function throws an exception, it is relayed to * the caller of the composed function. * * @param <V> the type of output of the {@code after} function,  and of the * composed function * @param after the function to apply after this function is applied * @return a composed  function that first applies this function and then * applies the {@code after} function * @throws NullPointerException if after is null * * @see #compose(Function) */ default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t) -> after.apply(apply(t)); } /** * Returns a function that always returns its input argument. * * @param <T> the type of the input and output objects to the function * @return a function that always returns its input argument */ static <T> Function<T, T> identity() { return t -> t; }}Copy the code

(1) Abstract method: apply

The abstract method R apply(T T) obtains the result of type R based on the parameters of type T.

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

Examples are as follows:

*/ @test public void applyMethodTest() {// String integer String numStr = "123456"; Integer num = applyMethod(numStr, n -> Integer.parseInt(n)); System.out.println(num); } public Integer applyMethod(String str, Function<String, Integer> function) { return function.apply(str); }Copy the code

(2) Method: compose

Method

compose(Function< V, R> compose) super V, ? Extends T> before), gets the function of apply.

/** * Returns a composed function that first applies the {@code before} * function to its input, and then applies this function to the result. * If evaluation of either function throws an exception, it is relayed to * the caller of the composed function. * * @param <V> the type of input to the {@code before} function,  and to the * composed function * @param before the function to apply before this function is applied * @return a composed function that first applies the {@code before} * function and then applies this function * @throws NullPointerException if before is null * * @see #andThen(Function) */ default <V> Function<V, R> compose(Function<? super V, ? extends T> before) { Objects.requireNonNull(before); return (V v) -> apply(before.apply(v)); }Copy the code

(3) Method: andThen

Function

andThen(Function
After) for combined operations, i.e., “do something first, then do something” scenarios.
,>

/** * Returns a composed function that first applies this function to * its input, and then applies the {@code after} function to the result. * If evaluation of either function throws an exception, it is relayed to * the caller of the composed function. * * @param <V> the type of output of the {@code after} function,  and of the * composed function * @param after the function to apply after this function is applied * @return a composed  function that first applies this function and then * applies the {@code after} function * @throws NullPointerException if after is null * * @see #compose(Function) */ default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) { Objects.requireNonNull(after); return (T t) -> after.apply(apply(t)); }Copy the code

Functional programming

Functional programming is not a new concept in Java. It treats computer operations as functions. The most important foundation of functional programming is the lambda calculus, and the functions of the lambda calculus can accept functions as inputs (parameters) and outputs (return values).

Compared with instruction programming, functional programming emphasizes the importance of function calculation over instruction execution.

In contrast to procedural programming, functional programming allows a function to be evaluated at any time.

Of course, Java is known as an object-oriented programming language, and everything is based on the characteristics of objects (abstraction, encapsulation, inheritance, polymorphism). Before JDK1.8, we focused on what attributes an object should have, which is of course the core of object orientation — abstracting data. However, with the advent of JDK1.8, this has started to change, and there seems to be a greater focus on a certain kind of common behavior (sort of like interfaces) in certain scenarios, which is the purpose of functional programming in JDK1.8. The figure below illustrates the transition from object-oriented programming to functional programming.

Lambda expressions are better examples of functional programming, and in order to support Lambda expressions, functional interfaces are created.

In addition, Java has added Lambda expressions at the language level in order to make the code easier to maintain and run on multi-core cpus when facing large data sets and for more efficient development. In the last section, we saw how useful Lambda expressions are.

In JDK1.8, functional programming is everywhere, and it’s fun to use, for example, a Stream.

The advantages of functional programming are as follows:

1. Simple code and fast development

Functional programming uses a lot of functions to reduce the repetition of code, so the program is shorter and faster to develop.

2. Close to natural language and easy to understand

Functional programming has the freedom to write code that is close to natural language.

For example, if two numbers differ only, we can write (x, y) -> x — y

3. Easier code management

Functional programming does not depend on, and does not change, the state of the outside world. Given an input parameter, the result must be the same. Therefore, each function can be treated as an independent unit, which is good for unit testing and debugging, as well as modular combinations.

4. Easy “concurrent programming”

Functional programming does not need to consider “deadlocks” because it does not modify variables, so there is no problem of “locking” threads at all. You don’t have to worry about one thread’s data being modified by another, so you can safely spread the work across multiple threads, deploying “concurrent programming.”

5. Hot upgrades of code

Functional programming has no side effects, as long as the interface stays the same and the internal implementation is externally independent. As a result, code can be upgraded directly while running, with no need for reboot or downtime.

Four,

Functional interfaces/programming will be everywhere in JDK1.8, and there are some new features that will help you understand better. As for functional interfaces, the specific features and usage will be shown most vividly in the following sections.

Do you agree with the functional interfaces proposed in JDK1.8?

References:

1. www.cnblogs.com/dorae/p/776…

2. blog.csdn.net/stormkai/ar…

3.baike.baidu.com/item/ Functional programming