How to write fennel: About the function transfer syntax sugar in JAVA: lambda

Solved problem: implement function delivery in Java.

In the practice of Java programming, there are some scenarios where we hope to pass functions in. Different function implementations represent different strategies. Before JDK8, an interface needs to be defined, and the function method is defined in this interface, and then passed Different implementation classes of this interface are added to implement different strategies. In JDK8 and later, lambda expressions can be used for simplification.

Before JDK8, we wanted to implement a strategy for getting data from different databases, as follows:

/**
 * 定义接口,从某一数据源获取数据
 */
public interface GetStrategy(){
    
    Bean get();

}
/**
 * 实现类:Mysql。
 */
public class MysqlGetStrategy(){
    private MysqlDao mysqlDao;
    Bean get(){
        return mysqlDao.get();
    }
} 
/**
 * 实现类:Squirrel
 */
public class RedisGetStrategy(){
    private RedisDao redisDao;
    Bean get(){
        return redisDao.get();
    }
}

/**
 * 获取数据后再处理数据
 */
public class Processor(){
    private GetStrategy getStrategy;
    public Processor(GetStrategy getStrategy){
        this.getStrategy = getStrategy;
    }
    private void process(){
        Bean bean = getStrategy.get();
        // process bean
    }
}

public static void main(String[] args){
    GetStrategy getStrategy = new MysqlGetStrategy();
    Processor processor = new Processor(getStrategy);
    processor.process();
}

It can be seen that the above code is relatively complicated. In order to pass the function (that is, the get method) to the Processor, we need

  1. Define an interface GetStrategy
  2. define an implementation class

Of course, we can simplify the above code by using an anonymous inner class, as shown below:

/**
 * 定义接口,从某一数据源获取数据
 */
public interface GetStrategy(){
    
    Bean get();

}

/**
 * 获取数据后再处理数据
 */
public class Processor(){
    private GetStrategy getStrategy;
    public Processor(GetStrategy getStrategy){
        this.getStrategy = getStrategy;
    }
    private void process(){
        Bean bean = getStrategy.get();
        // process bean
    }
}

public static void main(String[] args){
    
    Processor processor = new Processor(new GetStrategy(){
        public Bean get(){
            return MysqlDao.get();
        }
    });
    processor.process();
}

But the above code is still relatively complicated, complicated in

  1. Still need to define an interface GetStrategy.
  2. When creating an anonymous inner class, it is still more complicated, and the method name needs to be rewritten.

After JDK1.8, Lambda expression is provided, which solves the problem of function delivery, and does not require us to do complicated interface definition and implementation class definition, as follows

private class Processor{
    /**
     * JDK 自定义函数,无参,有返回值。
     */
    private Supplier<Bean> supplier;
    
    public Processor(Supplier<Bean> supplier){
        this.supplier = supplier;
    }
    
    public void process(){
        Bean bean = supply.supply();
        // process逻辑
    }
}

public static void main(String[] args){
    Supply<Bean> supply = MysqlDao::get;
    Processor processor = new Processor(supply);
    processor.process();
}

As you can see from the above code, the implementation of this syntactic sugar is

  1. In the java.util.function package, many different types of interfaces (such as the Supplier interface mentioned above) are defined to replace the interfaces defined by themselves (such as GetStrategy in the first and second code snippets)
  2. Use lamdba expressions to simplify the creation of anonymous classes (such as MysqlDao::get).

The alternative code is as follows:

/**
 * JDK8以下:定义接口,从某一数据源获取数据
 */
public interface GetStrategy(){
    Bean get();
}

/**
 * JDK8替代:JDK自带Supplier接口
 */
Supplier<Bean> supplier

/**
 * JDK8以下匿名内部类
 */
new GetStrategy(){
        public Bean get(){
            return MysqlDao.get();
        }
    });

/**
 * JDK8替代:lambda匿名内部类表达方式
 */
MysqlDao::get

About the custom interface in java.util.function in JDK8

In the java.util.function package, there are many different interfaces used to replace some simple interface definitions, including Consumer, Supplier, Function, BiFunction, etc., which correspond to different function implementations and can cover most function definitions .

Consumer defines a function with one parameter and no return value.

BiConsumer defines a function with two parameters and no return value.

Supplier defines a function with a return value and no parameters.

Function defines a function with a return value and parameters.

BiFunction defines a function with a return value and two parameters.

However, in some scenarios with too many function parameters, such as three parameters and four parameters, there is no corresponding implementation in the java.util.function package. If we need parameters with return values, we can introduce the following jar Bag.

<dependency>
    <groupId>io.vavr</groupId>
    <artifactId>vavr</artifactId>
    <version>0.9.0</version>
</dependency>

It can support a Function interface with up to 8 parameters. As for more than 8 parameters, we may have to re-examine whether this function can be refactored to reduce the number of parameters.

About FunctionalInterface annotation

effect:

The interface marked with this FunctionalInterface annotation will check whether the marked type conforms to the function interface definition at compile time.

Note:

From the point of view of the purpose of checking and reporting errors, the annotation FunctionalInterface is rather weak, because we need to write the interface. If this functional interface has been used in the form of lambda expression, then it is in compliance with the specification. If it does not conform to the specification , we will report an error when we use it, and we can achieve the purpose of checking errors at compile time when we use it.

From the point of view of labeling this as a functional interface, that is, it is useful.

The following are the annotations of the translated FunctionalInterface.

An informative annotation type used to indicate that an interface type declaration is intended to be a functional interface as defined by the Java Language Specification.

An annotation used to define that an interface is a functional interface as defined by the Java Language Specification.

Conceptually, a functional interface has exactly one abstract method. Since default methods have an implementation,‘they are not abstract.

Conceptually, a functional interface has one and only one abstract method. Since the default methods have already been implemented, they are not abstract.

If an interface declares an abstract method overriding one of the public methods of java.lang.Object,

If an abstract method declared by an interface overrides a public method in Object,

that also does not count toward the interface's abstract method count since any implementation of the interface will have an implementation from java.lang.Object or elsewhere.

Then this is not in compliance with the regulations, because the abstract method of this interface inherits the implementation of the parent class.

Note that instances of functional interfaces can be created with lambda expressions, method references, or constructor references.

Note: Instances of functional interfaces can be created using lambda expressions, method references, or constructor references.

If a type is annotated with this annotation type, compilers are required to generate an error message unless:

If a type uses this annotation, the compiler will check the following items, and an error will be reported if it does not match.

The type is an interface type and not an annotation type, enum, or class.

This type is an interface type, not an annotation, enum, or class.

The annotated type satisfies the requirements of a functional interface.

The annotated type is a functional interface.

However, the compiler will treat any interface meeting the definition of a functional interface as a functional interface regardless of whether or not a FunctionalInterface annotation is present on the interface declaration.

However, regardless of whether this annotation is used or not, the compiler will regard the interface that conforms to the definition of the functional interface as the functional interface.

Guess you like

Origin blog.csdn.net/whodarewin2005/article/details/129886744