Java 8 learning method references notes

I. Overview

What is the method references? We first look at an example:

After learning of lambda expressions, we often use the method to create an anonymous lambda expression. However, sometimes we just call a method that already exists. such as:

Arrays.sort(stringsArray,(s1,s2)->s1.compareToIgnoreCase(s2));

Which, compareToIgnoreCase is a method of the String class that already exists, so we can use the method reference format for writing:

Arrays.sort(stringsArray, String::compareToIgnoreCase);

String :: compareToIgnoreCase is a way to reference (Method Reference).

 

Second, what is the reference method

Reference method is used to directly access the class constructor or a method or existing instance. When the Lambda expressions just execute a method call, without Lambda expressions, by means of a direct reference in the form of higher readability. Reference method is a more concise and understandable Lambda expressions. The method provides a way of reference without performing the method of reference, the type of context requires that the target composed of a compatible interface function. Calculation, refer to an instance method (Lambda created as a function of the interface instance) creates a functional interface.

Simply put, a Lambda expression. In Java 8, we will use Lambda expressions create an anonymous method, but sometimes, we Lambda expressions may only invoke a method that already exists, without doing anything else, in this case, by a method name to refer to this existing method will be more clear, Java method 8 references allow us to do so. Reference method is a more compact, easy to read Lambda expressions, note that reference is a method of Lambda expression, wherein the method cited operator is double colon "::."

Note that the reference is a Lambda expression method, wherein the method cited operator is double colon "::."

 

Third, the method of reference example

Look at an example, first define a Person class, as follows:

package com.demo.model;

import java.time.LocalDate;

public class Person {

    public Person(String name, LocalDate birthday) {
        this.name = name;
        this.birthday = birthday;
    }

    String name;
    LocalDate birthday;

    public LocalDate getBirthday() {
        return birthday;
    }

    public static int compareByAge(Person a, Person b) {
        return a.birthday.compareTo(b.birthday);
    }

    @Override
    public String toString() {
        return this.name;
    }
}

Suppose we have an array of Person and want to sort it, this time, we might write:

Original wording, the use of anonymous class:

package com.demo;

import java.time.LocalDate;
import java.util.Arrays;
import java.util.Comparator;
import org.junit.Test;
import com.demo.model.Person;

public class testMethodReference {

    @Test
    public void test() {
        Person[] pArr = new Person[]{
                new Person("003", LocalDate.of(2016,9,1)),
                new Person("001", LocalDate.of(2016,2,1)),
                new Person("002", LocalDate.of(2016,3,1)),
                new Person("004", LocalDate.of(2016,12,1))};

        // 使用匿名类
        Arrays.sort(pArr, new Comparator<Person>() {
            @Override
            public int compare(Person a, Person b) {
                return a.getBirthday().compareTo(b.getBirthday());
            }
        });
        
        System.out.println(Arrays.asList(pArr));
    }
}

Wherein, sort method Arrays class is defined as follows:

public static <T> void sort(T[] a, Comparator<? super T> c)

Here, we must first note that Comparatorthe interface is a function interface, so we can use Lambda expressions, without the need to define an implementation Comparatorclass interface and creates an instance of the object passed to sort.

Use Lambda expressions, we can write:

Improved First, use Lambda expressions, not to call existing methods

@Test
public void test1() {
    Person[] pArr = new Person[]{
            new Person("003", LocalDate.of(2016,9,1)),
            new Person("001", LocalDate.of(2016,2,1)),
            new Person("002", LocalDate.of(2016,3,1)),
            new Person("004", LocalDate.of(2016,12,1))};
    
    //使用lambda表达式
    Arrays.sort(pArr, (Person a, Person b) -> {
        return a.getBirthday().compareTo(b.getBirthday());
    });
    
    System.out.println(Arrays.asList(pArr));
}

However, in the above code, compare the two methods on the birthday of the Person class has been defined, so we can use the existing method Person.compareByAge directly.

Improved Second, the use Lambda expressions, calling existing methods

@Test
public void test2() {
    Person[] pArr = new Person[]{
            new Person("003", LocalDate.of(2016,9,1)),
            new Person("001", LocalDate.of(2016,2,1)),
            new Person("002", LocalDate.of(2016,3,1)),
            new Person("004", LocalDate.of(2016,12,1))};
    
    //使用lambda表达式和类的静态方法
    Arrays.sort(pArr, (a ,b) -> Person.compareByAge(a, b));
    
    System.out.println(Arrays.asList(pArr));
}

Because the Lambda expression invokes a method that already exists, so we can use the direct method referenced in place of the Lambda expressions.

Improved Third, use references

@Test
public void test3() {
    Person[] pArr = new Person[]{
            new Person("003", LocalDate.of(2016,9,1)),
            new Person("001", LocalDate.of(2016,2,1)),
            new Person("002", LocalDate.of(2016,3,1)),
            new Person("004", LocalDate.of(2016,12,1))};
    
    //使用方法引用,引用的是类的静态方法
    Arrays.sort(pArr, Person::compareByAge);
    
    System.out.println(Arrays.asList(pArr));
}

operation result:

[001, 002, 003, 004]

In the above code, the method references Person :: compareByAge semantically and Lambda (a, b) -> Person.compareByAge (a, b) are identical , have the following characteristics:

  • Parameter is true Comparator <Person> .compare method copy from, i.e. (Person, Person);
  • Expressions body calls Person.compareByAge method.

 

Fourth, the four methods reference types

The method is referenced standard form: 类名::方法名. ( Note: only need to write the method name, no need to write parentheses )

There are four types of method references:

Types of Examples
Reference a static method ContainingClass::staticMethodName
An object reference to an instance method containingObject::instanceMethodName
Examples of the method of any reference to a type of object ContainingType::methodName
Reference constructor ClassName::new

 

 

 

 

Way to learn these forms of reference:

1, the static method reference

Composition syntax: ClassName :: staticMethodName

We give examples above Person :: compareByAge is a static method reference.

note:

  • Static method references easier to understand, and compared to the static method call, just  Replaced  ::
  • Anywhere in the target type is compatible, you can use the static method reference.

example:

  String :: valueOf equivalent to the lambda expression (s) -> String.valueOf (s)

     Math :: pow lambda expression is equivalent to (x, y) -> Math.pow (x, y);

Examples inverted string:

package com.demo;

/**
 * 函数式接口
 */
public interface StringFunc {
    
    String func(String n);
}
package com.demo;

public class MyStringOps {
    
    //静态方法: 反转字符串
    public static String strReverse(String str) {
        String result = "";
        for (int i = str.length() - 1; i >= 0; i--) {
            result += str.charAt(i);
        }
        return result;
    }

}
package com.demo;

public class MethodRefDemo {
    
    public static String stringOp(StringFunc sf, String s) {
        return sf.func(s);
    }
    
    public static void main(String[] args) {
        String inStr = "lambda add power to Java";
        //MyStringOps::strReverse 相当于实现了接口方法func() 
        // 并在接口方法func()中作了MyStringOps.strReverse()操作
         String outStr = stringOp(MyStringOps::strReverse, inStr);
        System.out.println("Original string: " + inStr);
        System.out.println("String reserved: " + outStr);
    }

}

Output:

Original string: lambda add power to Java
String reserved: avaJ ot rewop dda adbmal

MyStringOps :: strReverse expression evaluates to an object reference, wherein, provided StringFunc StrReverse of func (implemented) method.

Find the list of objects with maximum

package com.demo;

public class MyClass {

    private int val;

    MyClass(int v) {
        val = v;
    }
    
    public int getValue() {
        return val;
    }

}
package com.demo;

import java.util.ArrayList;
import java.util.Collections;

public class UseMethodRef {
    
     public static int compareMC(MyClass a, MyClass b) {
         return a.getValue() - b.getValue();
     }
     
     public static void main(String[] args) {
         ArrayList<MyClass> a1 = new ArrayList<MyClass>();
         a1.add(new MyClass(1));
         a1.add(new MyClass(4));
         a1.add(new MyClass(2));
         a1.add(new MyClass(9));
         a1.add(new MyClass(3));
         a1.add(new MyClass(7));
         //UseMethodRef::compareMC生成了抽象接口Comparator定义的compare()方法的实例。
         MyClass maxValObj = Collections.max(a1, UseMethodRef::compareMC);
         System.out.println("Maximum value is: " + maxValObj.getValue());
    }

}

Output:

Maximum value is: 9

UseMethodRef defines a static method compareMC (), which defined the Comparator compare () method is compatible. Therefore, there is no need to explicitly implement the Comparator interface and create an instance.

2, a specific example method of object reference

This syntax and grammar for static methods is similar, but here the use of an object reference instead of the class name. Examples of the method is divided into the following three types of references:

a. Examples of the method of reference example

Composition syntax: instanceReference :: methodName

The following example, a method is cited a method myComparisonProvider compareByName object.

class ComparisonProvider{
    
    public int compareByName(Person a, Person b){
        return a.getName().compareTo(b.getName());
    }

    public int compareByAge(Person a, Person b){
        return a.getBirthday().compareTo(b.getBirthday());
    }
}

ComparisonProvider myComparisonProvider = new ComparisonProvider();
Arrays.sort(rosterAsArray, myComparisonProvider::compareByName);

Example: Reverse a string 

package com.demo;

/**
 * 函数式接口
 */
public interface StringFunc {
    
    String func(String n);
}
package com.demo;

public class MyStringOps {
    
    //普通方法: 反转字符串
    public String strReverse1(String str) {
        String result = "";
        for (int i = str.length() - 1; i >= 0; i--) {
            result += str.charAt(i);
        }
        return result;
    }

}

 

package com.demo;

public class MethodRefDemo2 {

    public static String stringOp(StringFunc sf, String s) {
        return sf.func(s);
    }
    
    public static void main(String[] args) {
        String inStr = "lambda add power to Java";
        MyStringOps strOps = new MyStringOps();//实例对象
        //strOps::strReverse1 相当于实现了接口方法func() 
        String outStr = stringOp(strOps::strReverse1, inStr);

        System.out.println("Original string: " + inStr);
        System.out.println("String reserved: " + outStr);
    }

}

Output:

Original string: lambda add power to Java
String reserved: avaJ ot rewop dda adbmal

b. Examples of the method on reference to the superclass

Composition syntax: Super :: methodName

The name of the method specified by the methodName, through the use of Super , can refer to the method of the superclass version.

Can also capture this pointer, this :: equals lambda expression is equivalent to x -> this.equals (x);

c. Examples of the method of the type cited

Composition syntax: ClassName :: methodName

note:

If the type of instance method is generic, it is necessary to provide delimiter type prior :: parameters, or (most case) using the target type derives its type.

Static methods and instance methods on the reference type reference has the same syntax. The compiler will make a decision based on the actual situation. Generally, we do not need to specify the method cited in the parameter type because the compiler can often derived results, but if necessary we can also explicitly supply information before parameter types :: separator.

example:

String :: toString equivalent to the lambda expression (s) -> s.toString ()

Here less readily appreciated, instances to be invoked by the subject method, the first parameter corresponding to a reference method Lambda, Lambda will be subject example method call.

Or in a generic class in the generic method, a method may be used references.

package com.demo;

public interface MyFunc<T> {
    
    int func(T[] als, T v);
}
package com.demo;

public class MyArrayOps {

     public static <T> int countMatching(T[] vals, T v) {
         int count = 0;
         for (int i = 0; i < vals.length; i++) {
             if (vals[i] == v) count++;
         }
         return count;
     }

}
package com.demo;

public class GenericMethodRefDemo {
    
    public static <T> int myOp(MyFunc<T> f, T[] vals, T v) {
        return f.func(vals, v);
    }
    
    public static void main(String[] args){
        Integer[] vals = {1, 2, 3, 4, 2, 3, 4, 4, 5};
        String[] strs = {"One", "Two", "Three", "Two"};
        int count;
        count=myOp(MyArrayOps::<Integer>countMatching, vals, 4);
        System.out.println("vals contains "+count+" 4s");
        count=myOp(MyArrayOps::<String>countMatching, strs, "Two");
        System.out.println("strs contains "+count+" Twos");
    }

}

operation result: 

vals contains 3 4s
strs contains 2 Twos

analysis:

      In the program, MyArrayOps non-generic type, comprising a generic method countMatching (). The method returns the number of matching a specified value in the array elements. Note here how to specify generic type parameters. For example, the main () method, the first countMatching () method of the first call as follows: count = myOp (MyArrayOps :: <Integer> countMatching, vals, 4); where the transfer type parameter Integer.

      Note that, the parameters passed back in place in ::. This syntax can be extended. When the generic method is specified as a reference method, the type parameters appear after ::, method name before. However, it should be noted that, in this case (and in many other cases), does not have to specify the type of display parameters, because the type parameters are automatically inferred. In the case of the specified generic class type parameter class name :: behind the front.

3, any object (of the same class) of the reference example method

The following example, where a reference to any object is a method compareToIgnoreCase string array.

String[] stringArray = { "Barbara", "James", "Mary", "John", "Patricia", "Robert", "Michael", "Linda" };
Arrays.sort(stringArray, String::compareToIgnoreCase);

Note: This compareToIgnoreCase methods are not static methods, so call needs to instantiate the object can be called normal. It is here embodied, any reference to an object is a method compareToIgnoreCase string array.

4, reference constructor

Constructor constructor references cited divided and array reference constructor.

a. reference constructor (the constructor may also be referred to as a reference)

Composition syntax: Class :: new new

It is the constructor method is essentially static, but rather special method name, using the new keyword .

example:

String :: new, equivalent to the lambda expressions () -> new String () 

package com.demo;

public interface MyFunc1 {

    MyClass func(int n);

}
package com.demo;

public class MyClass {

    private int val;

    MyClass(int v) {
        val = v;
    }
    
    MyClass(){
        val = 0;
    }
    
    public int getValue() {
        return val;
    }

}
package com.demo;

public class ConstructorRefDemo {

    public static void main(String[] args) {
        MyFunc1 myClassCons = MyClass :: new;
        MyClass mc = myClassCons.func(100);
        System.out.println("val in mc is: " + mc.getValue());
    }
}

Output:

val in mc is: 100

b. an array reference constructor

Composition syntax: the TypeName [] :: new new

example:

int [] :: new is a constructor parameter containing a reference, this parameter is the length of the array. It is equivalent to the lambda expression x -> new int [x].

The virtual presence array constructor method (function interface) receives a parameter int:

IntFunction<int[]> arrayMaker = int[]::new;
int[] array = arrayMaker.apply(10) // 创建数组 int[10]

 

Published 61 original articles · won praise 9 · views 30000 +

Guess you like

Origin blog.csdn.net/qq_33204444/article/details/105036184