Java8 Detailed Explanation of the (two): lambda expressions method reference


Parametric pass codes help to respond to changing needs through behavior, methods and lambda expressions is Java8 reference to behavioral parameters of the new practice. Lambda expressions and references not only to practice the methods of behavioral parameters, but also greatly simplifies the code.

1 Lambda Expressions

1.1 Lambda properties

Lambda expressions, is a way of transmitting the anonymous function may have the following characteristics:

  • No name.
  • Lambda functions, do not belong to a particular class (belonging to a particular class methods), with the parameter list, the function body, return type, and exception list.
  • Lambda expressions can be passed as a parameter to a method or an assignment to a variable.
  • The whole expression is the return value.

1.2 Lambda basic grammar

Lambda expressions consists of three parts: the list of parameters, arrow, Lambda body. List of parameters, i.e. parameters of the function interface methods, Lambda Lambda is the return value of the body, for blocking the arrow only two parts.

参数列表 --> Lambda主体
(parameters) -> expression

(Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight());
// 没有参数
() -> 42;
// Lambda主体有多条,并且有返回值情况
(Apple a1, Apple a2) -> { 
    return a1.getWeight().compareTo(a2.getWeight());
};

Use Scene 2 - Functional Interface

2.1 Functional Interface

Only when necessary functional interface can transfer Lambda. Interface function is only an abstract definition of the interface method. E.g:

public interface Runnable
public interface Comparator<T>
public interface Callable<V>
public interface FileFilter

Need some attention:

  • Interface can be the default method, the present method does not affect the function of the default interface.
  • If the interface declares an abstract method for covering public methods Object class, which is not included in the abstract method in a number of interface functions. Comparator interface has two abstract methods, but is still a function of the interface interface.
@FunctionalInterface   // 用于标注当前接口为函数式接口
public interface Comparator<T> {
    int compare(T o1, T o2);
    boolean equals(Object obj); // 覆盖Object的equals方法
}

Lambda is a specific implementation of the interface function , implemented within the form which is provided with an abstract interface methods, and the whole Lambda expressions as an example of the interface. Lambda expressions can thus be assigned to variables, it may be used as a method to pass parameters.

2.2 Java8 introduce new functions interface

Abstract method signature can be described as the signature Lambda expressions. Abstract method signature function is called a function interface descriptor.
In Java 8 java.util.function introduced several kinds of functions packet interface. E.g

Functional Interface Functions descriptor Note A scene that can be used
Predicate T -> boolean Defined test method T accepts generic object and returns a boolean. Boolean expression
BiPredicate<L,R> (L,R) -> boolean Define test methods, T and U accepts generic type object, returns a boolean
Consumer T -> void The method defined accept, accept the T generic object did not return (void). Consumer Objects
BiConsumer<T,U (T,U) -> void The method defined accept, accept the generic type of the object T and U, there is no return (void)
Function<T,R> T -> R Apply the definition method, which takes a generic target T and R of the generic object returns. Alternatively or extracted from a subject
BiFunction<T,U,R> (T,U) -> R Apply the definition method, which takes a generic type of the object T and U, and R is a generic Object returned. comparisons
Supplier () -> T Defined get method, there is no input, returns a generic object of type T Create a new object
UnaryOperator T -> T Inherited from Function Interface The combined value
BinaryOperator (T,T) -> T Interfaces inherited from BiFunction

Functional interfaces often use generics, but they can only be bound to a generic reference type. For basic data types, Java converted by autoboxing reference type mechanism. The nature of the packing process is to wrap up the original type, holds the heap memory, so the packing operations consume some memory. Automatic packing operation in order to avoid the input and output of the original type, java.util.function package provides many special version of the interface functions, e.g. IntPredicate ToIntFunction interfaces and interfaces.

// 入参是int类型,出参是泛型
public interface IntFunction<R> {
    R apply(int value);
}
// 入参是泛型,出参是int类型
public interface ToIntFunction<T> {
    int applyAsInt(T value);
}

3 type inference and type checking

3.1 type inference

Lambda expressions can be passed as a parameter to the method can also be assigned to a variable. Type inference, it refers to the type of Lambda expressions inferred by these contexts. In the above code example, the type judgment Analysis

  1. From filterApples method calls to find the definition method.
  2. The second parameter is the definition of Type Predicate - target type.
  3. Predicate interface is a function, comprising a test only abstract method returns a Boolean value accept the T type, which is a function descriptor T -> boolean.
  4. Lambda expressions matching function descriptor.
// 方法调用
List<Apple> heavyApples = filterApples(inventory, (Apple apple) -> "green".equals(apple.color) && apple.getWeight() > 150);

// Apple类方法定义
public static List<Apple> filterApples(List<Apple> inventory, Predicate<Apple> predicate) {
    List<Apple> result = new ArrayList<>();
    for (Apple apple : inventory) {
        if (predicate.test(apple)) {
            result.add(apple);
        }
    }
    return result;
}

// java.util.function包接口
public interface Predicate<T> {
    boolean test(T var1);
}

Note that there is

  • void compatible rules. Functional Interface void return type compatible with the type of the parameter list still requires compatible.
// Predicate返回boolean,但也兼容void
Predicate<String> p = s -> list.add(s);
  • Although the super class Object class, but not functional interfaces, incompatible Lambda expressions.

3.2 Lambda signature type inference

As the compiler inferred from context Lambda expressions interface function, it may be inferred Lambda signature, i.e. signature function interface of abstract methods.
The above method is called the transformation of the form

List<Apple> heavyApples = filterApples(inventory, apple) -> "green".equals(apple.color) && apple.getWeight() > 150);
  • When the parameter list is only one parameter, you can omit the parentheses.

4 Lamda restrictions on the use of

4.1 variable limits

Lambda without limitation, can be captured (in which the body reference) static variables and instance variables. However, local variables must be explicitly declared as final, or in fact final (assigned only once).

Implementation instance and local variables behind a different key. Instance variables are stored in stack, local variables are stored on the stack. And a Lambda Java8 anonymous classes can do things like closures: they can be used as a method to pass parameters and variables can be accessed outside its scope. But there is a limitation: they can not modify the contents of local variables in a method defined Lambda. These variables must be implicitly final. Lambda can be considered a value-closed, rather than variable closed. The reason for this limitation is that the presence of local variables stored on the stack, and they are only implicit representation threads located thereon. If capture allows local variables can be changed, it will lead to creating new possibilities thread safe.

4.2 this usage

The main difference between this distinction and the Lambda anonymous inner class here. In the Lambda, this points to an external class Lamba is located, and anonymous inner classes this is an anonymous inner class of the current object.

5 reference method

Method references so that you can reuse existing method definition. The method can be seen as a quick reference to the wording of Lambda only invoke a particular method allows you to achieve to create Lambda expressions based on existing methods.

目标引用::方法名称

Method references a total of four.

  • :: class instance methods
@Test
public void testClassMethod() {
    File[] hiddenFilesInnerClass = new File(".").listFiles(new FileFilter() {
        public boolean accept(File file) {
            return file.isHidden();
        }
    });
    File[] hiddenFilesLambda = new File(".").listFiles(file -> file.isHidden());
    File[] hiddenFilesMethodRef = new File(".").listFiles(File::isHidden);
}
  • :: class static method
@Test
public void testStaticMethod() {
    IntegerFunction function = Integer::parseInt;
    System.out.println(method(function, "12"));
}

public Integer method(IntegerFunction integerFunction, String str) {
    return integerFunction.apply(str);
}

public interface IntegerFunction {
    Integer apply(String str);
}
  • Examples cited an instance method ::
@Test
public void testReferenceMethod(){
    // 创建一个实例
    MethodReferenceTest mrt = new MethodReferenceTest();
    System.out.println(method(mrt::parseInt,"42"));
}

public Integer parseInt(String str) {
    return new Integer(42);
}
  • Constructor references - class name: new
@Test
public void testConstructMethod(){
    Supplier<Student> supplier = Student::new;
    Function<String,Student> function = Student::new;
    Student student = function.apply("lzp");
}

public class Student{
    private String name;

    public Student() {
        this.name = "lzp";
    }

    public Student(String name) {
        this.name = name;
    }
    /*省略getter/setter*/
}

When using the constructor references, the need for signature matching constructor function interface, if there is no ready-made interfaces, you need to customize.

6 practice cases

Student class definitions

public class Student {
    private String name;
    private Integer height;

    public Student(String name, Integer height) {
        this.name = name;
        this.height = height;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getHeight() {
        return height;
    }

    public void setHeight(Integer height) {
        this.height = height;
    }
}

optimization process

public class StudentSortDemo {

    public static void main(String[] args) {
        List<Student> students = Arrays.asList(new Student[]{new Student("Ming", 120), new Student("Ping", 160)});
        // 匿名内部类
        students.sort(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return o1.getHeight().compareTo(o2.getHeight());
            }
        });
        // Lambda
        students.sort((o1, o2) -> o1.getHeight().compareTo(o2.getHeight()));
        // 使用Comparator静态辅助方法与Lambda
        students.sort(Comparator.comparing(o -> o.getHeight()));
        // 使用Comparator静态辅助方法与方法引用
        students.sort(Comparator.comparing(Student::getHeight));
    }
}
Published 72 original articles · won praise 110 · views 90000 +

Guess you like

Origin blog.csdn.net/LIZHONGPING00/article/details/103691118