Detailed Explanation of Lambda Expression and Functional Interface

1. Preface: Three programming paradigms

Programming syntax has been developed for decades, and various programming languages ​​are flourishing, such as C, Python, and Java, which dominate the list all the year round. After such a long evolution, the programming world has gradually derived three major programming paradigms.

So what is a programming paradigm?

Programming paradigm refers to a typical programming style in software engineering , and it is the design style used to design the program structure. The current mainstream programming paradigms are: structured programming, functional programming, object-oriented programming, etc. Different programming paradigms have different characteristics and applicable scenarios.

structured programming

That is, process-oriented programming is a programming paradigm and a unique 自顶向下programming idea. It uses structures such as subroutines, program code blocks, for loops, and while loops to organize code. A structured program is composed of some simple and hierarchical program flow frameworks, which can be divided into sequence , selection and repetition . C language is a typical structured programming language.

A structured language is easier to program than an unstructured language. It is completely in line with people's thinking habits. The process is the process, which refers to the steps of doing things: what to do first, what to do, and what to do next. Writing a program based on this idea is like designing a assembly line. In Java, the main method is such a pipeline.

Object-Oriented Programming

Object-Oriented Programming (Object-Oriented Programming, for short OOP) is a mainstream programming paradigm. It uses objects as the basic unit of programs, and combines data and methods of operating data into objects to encapsulate one or more functions. An object in object-oriented programming is an instance of a class, which can have properties and methods. The core of object-oriented programming lies in abstraction, which provides clear object boundaries. Combining 封装、集成、多态features reduces code coupling and improves system maintainability.

In object-oriented programming, one thing to remember is that everything is an object . It also simulates the human way of thinking as much as possible, making the software development method and process as close as possible to the method and process of human understanding of the world and solving real problems. The masterpieces of object-oriented programming languages ​​are C++ and Java.

functional programming

Functional programming is also a programming paradigm that views computation 数学函数的求值as building programs by applying and composing functions. The core idea of ​​functional programming is to decompose the calculation process into a series of reusable functions, each of which accepts one or more input parameters and returns one or more output results. In functional programming, functions are viewed as 第一等公民. The so-called "first-class citizen" means that a function is on an equal footing with other data types, and can be assigned to other variables, or used as a parameter, passed to another function, or used as the return value of another function.

Object-oriented programming uses nouns to abstract the world, while functional programming 动词抽象世界uses A typical functional programming language is Scala. The author also came into contact with this language in the process of learning spark. The most basic features in it are various Lambda expressions and various grammatical sugar abbreviations. It was very novel at that time. . The characteristic of functional programming is that you no longer know where the data comes from. Each function is to organize smaller functions into larger functions. The parameters of functions are also functions, and the functions returned by functions are also functions. In the end, I got a super awesome function, and I just waited for others to use it to write a main function to fill in the data.

2. Insights from Lambda

Lambda expressions are one 匿名函数and can be passed as parameters of a function. In essence, Lambda expressions are a rewriting form of anonymous inner classes, which can be regarded as an interface type , so they can be passed as parameters and variables.

The grammatical form of Lambda expression: Shorthand logic: If there is only one parameter, "()" can be omitted, and if the method body has only one line of code, "{}" can be omitted.( 参数列表 ) -> { 方法体 }

Tip : The parameters in the parameter list do not need to declare the type, and will automatically match the formal parameter list in the interface abstract method.

PS : It is conditional that an anonymous inner class can be rewritten into a lambda expression: the implemented interface must be a functional interface , usually with an annotation mark @FunctionalInterface.

1. Anonymous inner class

As the name implies, an inner class is a class defined inside a class, and an anonymous inner class is an inner class without a name. Because there is no name, an anonymous inner class can only be used once, and it is usually used to simplify code writing. There is a prerequisite for using an anonymous inner class : an abstract class must be inherited or an interface must be implemented, so an anonymous inner class is essentially an object, which is a subclass object that implements the interface or inherits the abstract class.

Anonymous inner class syntax format:

new `抽象类名|接口名`() {
    
    
        实现方法;
    };

2. Functional interface

insert image description here

Functional interface , that is, functional interface. At present, the definition given in major articles is: an interface with and only one abstract method. This definition is precisely wrong. The precise definition should be: 有且仅有一个待实现的抽象方法的接口.

For example, the interface shown in the figure above Comparator<T>is a comparator interface provided by java, which is a Functional interface. Careful students must have discovered that there is not only one abstract method compare in this interface , but also an equals method, so it has two abstract methods, which overturns the above definition of "there is only one abstract method". But the equals method does not need to be implemented by itself, because each class inherits the Object class by default, and the implementation of the equals method has been provided in Object.

Therefore, the precise definition of the Function interface should be: an interface with one and only one abstract method to be implemented. Every lambda expression of that type will be matched against this abstract method. If you want to add additional functionality to your interface, you can add default methods to your functional interface.

We can use the lambda expression as the interface type that implements this abstract method. To ensure that your interface must meet this requirement, you only need to add @FunctionalInterfaceannotations If the compiler finds that you have more interfaces with this annotation than When an abstract method to be implemented, the following prompt will be given.
"Multiple non-overriding abstract methods found in interface java8.lambda.Adder"

Example of a functional interface:

@FunctionalInterface
interface Action<T,F>{
    
    
    T run(F f);
}

3. Lambda rewriting case

Let's use a sorted example to understand how to rewrite a long-winded anonymous inner class into a clean Lambda expression.

public class LambdaDemo1 {
    
    
    public static void main(String[] args) {
    
    
        //假如一个list中的元素要排序
        List<String> list = Arrays.asList("hello","tom","apple","bbc");
        //之前的排序是这样写的
        Collections.sort(list, new Comparator<String>(){
    
    
            @Override
            public int compare(String o1, String o2) {
    
    
                return -o1.compareTo(o2);
            }
        });
        System.out.println(list.toString());
    }
}

After rewriting using Lambda

public class LambdaDemo1 {
    
    
    public static void main(String[] args) {
    
    
        //假如一个list中的元素要排序
        List<String> list = Arrays.asList("hello","tom","apple","bbc");
        //使用Lambda表达式,如果是单条语句,可以省略大括号
        Collections.sort(list, (o1, o2) -> -o1.compareTo(o2));
        System.out.println(list.toString());
    }
}

Of course, the current IDEA is very smart. Moving the mouse over the anonymous inner class will prompt you whether to rewrite it into a lambda expression. This function can be said to be very convenient and practical.

Above we used the built-in Functional interface of java, and then we manually implemented a Functional interface to experience the usage of lambda.

Custom Functional interface

@FunctionalInterface
public interface Adder {
    
    
    int add(int a,int b);
}

An anonymous inner class implements an addition operation

public class AdderTest {
    
    
    public static void main(String[] args) {
    
    
        Adder adder = new Adder() {
    
    
            @Override
            public int add(int a, int b) {
    
    
                return a + b;
            }
        };

        System.out.println(adder.add(1,2));
    }
}

Rewritten into Lambda form

public class AdderTest {
    
    
    public static void main(String[] args) {
    
    
        Adder adder = (a, b) -> a + b;

        System.out.println(adder.add(1,2));
    }
}

Three, Lambda syntax sugar

If there is a method in the Lambda body that has been implemented, that is, there is a ready-made method whose parameter number, type, and return value type are exactly the same as the abstract method in the functional interface, then you can use method reference, which can also be understood as Method reference is another form of lambda expression, and its syntax is simpler than lambda expression. Java 8 allows you to use ::keywords to refer to methods.

1. Static method reference

form:类名::方法名

@FunctionalInterface
public interface Action {
    
    
    public String run(int Integer);
}
public class LambdaTest {
    
    
    public static void main(String[] args) {
    
    
        Action action=Integer::toString;
        System.out.println(action.run(9));
    }
}

2. Instance method reference

form:实例名::方法名

public class LambdaTest01 {
    
    
    public String test(int i){
    
    
        return "i="+i;
    }
    public static void main(String[] args) {
    
    
        LambdaTest01 t = new LambdaTest01();
        Action action=t::test;
        System.out.println(action.run(10));
    }
}
//特别的:System.out::println
public class LambdaTest03 {
    
    
    public static void main(String[] args) {
    
    
        Consumer<Integer> con = System.out::println;
        con.accept(200);
    }
}

3. Construction method reference

Form: 类名::new| 数组类型[]::new

//定义一个实体类People
public class People {
    
    
    private String name;
    public People() {
    
    

    }
    public People(String name) {
    
    
        this.name = name;
    }
    public void say(){
    
    
        System.out.println("我的名字是:"+name);
    }
}
//定义函数式接口CreatePeople
@FunctionalInterface
public interface CreatePeople {
    
    
    public People create(String name);
}
public class LambdaTest04 {
    
    
    public static void main(String[] args) {
    
    
        //会调用相应参数的构造器
        CreatePeople createPeople=People::new;
        People people = createPeople.create("kangkang");
        people.say();
    }
}
//数组引用案例
public class LambdaTest06 {
    
    
    public static void main(String[] args) {
    
    
        Function<Integer, String[]> fun1 = (x) -> new String[x];
        Function<Integer, String[]> fun2 = String[]::new;
        String[] array = fun2.apply(10);
    }
}

Four, four general functional interfaces

Schedule:

interface name abstract method features
Predicate boolean test(T t) Pass in T, return Boolean
Supplier T get() Create something out of nothing
Consumer void accept(T t) out of nothing
Function<T, R> R apply(T t) change T to R

1,Predicate

Assertion, an interface for conditional judgment

有参,有返回值,传入一个T,返回一个boolean

Example:

public class PredicateTest {
    
    
    public static void main(String[] args) {
    
    
        List<String> lists = Arrays.asList("Java", "html5","JavaScript", "C++", "hibernate", "PHP");
        //判断列表长度是否大于10
        Predicate<List> p1= list -> list.size()>10;
        boolean ans = p1.test(lists);
        System.out.println(ans);

        //判断列表是否包含"Java"
        Predicate<List> p2= list -> list.contains("Java");
        boolean ans2 = p2.test(lists);
        System.out.println(ans2);
    }
}

2,Supplier

Producer interface, create, produce, create something out of nothing

无参,有返回值T

Example:

public class SupplierTest {
    
    
    public static void main(String[] args) {
    
    
        //生成一个八位的随机字符串
        Supplier<String> supplier = ()->{
    
    
            String base = "abcdefghijklmnopqrstuvwxyz0123456789";
            Random random = new Random();
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < 8; i++) {
    
    
                //生成[0,base.length)之间的随机数
                int number = random.nextInt(base.length());
                sb.append(base.charAt(number));
            }
            return sb.toString();
        };
        String ans = supplier.get();
        System.out.println(ans);
    }
}

3,Consumer

consumer interface

消费一个T,不返回任何值

Example:

public class ConsumerTest {
    
    
    public static void main(String[] args) {
    
    
        Consumer<String>  consumer= System.out::print;
        consumer.accept("打印字符串");
    }
}

4,Function<T, R>

conversion interface

有参,有返回值,给定一个T,将之转换为R,并返回。

Interfaces come with default methods:

The "compose(Function)" method means that it is executed before a certain method, and the return is still a Function type

The "andThen(Function)" method means that it is executed after a certain method, and the return is still a Function type

Example:

public class FunctionTest {
    
    
    public static void main(String[] args) {
    
    
        //传入一个String类型名称,返回一个people对象
        Function<String,People> func= People::new;
        People p1=func.apply("kangkang");

        //需求改变:创建对象前给name加一个姓氏前缀,创建对象后获取姓名长度
        Function<String,String> before = s ->"wang-"+s;
        Function<People,Integer> after= s -> s.getName().length();
        //这段代码需要好好理解,逻辑是先对T应用before规则,再对R应用after规则
        Integer len = func.compose(before).andThen(after).apply("kangkang");
        System.out.println("姓名长度:"+len);
    }
}

insert image description here

Guess you like

Origin blog.csdn.net/qq_36756227/article/details/130243588