1. 程式人生 > 實用技巧 >Java8特性:方法引用

Java8特性:方法引用

一、是什麼?

方法引用是用來直接訪問類或者例項已經存在的方法或者構造方法。

二、哪裡能用?

當Lambda表示式中只是執行一個方法呼叫時。

三、怎麼理解?

這裡以Arrays的sort方法進行講解:public static <T> void sort(T[] a, Comparator<? super T> c)

public void introduce() {
    String[] strArray ={"a", "c", "b"};
    //在學完lambda表示式後,如果你想建立一個Comparator例項,你可能會用以下方法:
    Arrays.sort(strArray, (s1,s2)->s1.compareTo(s2));
        
    
//你仔細看就會發現整個lambda體其實就只是在呼叫String類的compareTo()方法而已 //因此我們可以使用方法引用的方式來進行簡寫 Arrays.sort(strArray,String::compareTo); }

四、有哪些?

  • 方法引用 ,形式有三種:1、例項::例項方法名 2、類名::靜態方法名 3、類名::例項方法名
  • 構造器引用 ,形式有一種: 類名::new
  • 陣列引用 ,形式有一種:型別[]::new

五、具體例子

準備:定義一個person類,欄位如下:

public class Person {
    private String name;
    
private int age; public Person(String name) { this.name = name; } public Person(String name, int age) { this.name = name; this.age = age; } //省略get/set方法... }

1. 例項::例項方法名

public void test1(){
    Person person=new Person("小明",18);
 
    Supplier<String> supplier=()->person.getName();
    System.out.println(supplier.get());
    
    
//上面lambda體只用到person例項的getName()方法,因此可以改寫成例項::例項方法名 Supplier<String> supplier1=person::getName; System.out.println(supplier1.get()); }

2.類名::靜態方法名

public void test2(){
    //普通lambda方式
    Comparator<Integer> com = (x, y) -> Integer.compare(x, y);
 
    //類名:靜態方法名
    Comparator<Integer> com2 = Integer::compare;
}

3. 類名::例項方法名,前提:Lambda 引數列表的第一個引數,是例項方法的呼叫者,第二個引數(或無參)是例項方法的引數。

public void test3() {
    String[] strArray = {"a", "c", "b"};
    Arrays.sort(strArray, (s1, s2) -> s1.compareTo(s2));
 
    //lambda的第一個引數s1 是例項方法compareTo()的呼叫者
    //且lambda的第二個引數s2 是compareTo()的引數
    Arrays.sort(strArray, String::compareTo);
}

4. 類名::new ,前提:構造器的引數列表,需要與函式式介面中引數列表保持一致

public void test4(){
    // Function的引數為String,匹配 public Person(String name)
    Function<String, Person> fun = Person::new;
 
    //BiFunction的引數為String,Integer,匹配 public Person(String name, int age)
    BiFunction<String, Integer, Person> fun2 = Person::new;
}

5.型別[]::new

public void test5() {
    Function<Integer, String[]> fun = (length) -> new String[length];
    String[] strs1 = fun.apply(10);
    System.out.println(strs1.length);
 
    System.out.println("--------------------------");
 
    Function<Integer, String[]> fun2 = String[]::new;
    String[] strs2 = fun2.apply(20);
    System.out.println(strs2.length);
}

6. 補充:

6.1. 當lambda體呼叫的方法是父類中的方法或者是當前類中的方法時,可以使用super::例項方法名 或 this::例項方法名

public class Father {
    public int add(int a, int b) {
        return a + b;
    }
}
 
public class Son extends Father {
    public int add(int a, int b) {
        return a + b + 2;
    }
 
    public int calculate(BiFunction<Integer, Integer, Integer> function, int a, int b) {
        return function.apply(a, b);
    }
 
    @Test
    public void test() {
        int fatherAdd = calculate(super::add, 1, 2);
        int sonAdd = calculate(this::add, 1, 2);
        System.out.println(fatherAdd);
        System.out.println(sonAdd);
    }
}
 
//執行結果:
3
5

6.2 當lambda體中的方法有泛型是,可以在雙冒號:: 之後指定型別。

public interface MyFunc<T> {
    int func(T[] als, T v);
}
 
public class MyArrayOps {
    //統計v在陣列中出現的次數
    public static <T> int countMatching(T[] array, T v) {
        int count = 0;
        for (T t : array) {
            if (t.equals(v)) count++;
        }
        return count;
    }
}
 
public class Run {
 
    public static <T> int myOp(MyFunc<T> f, T[] array, T v) {
        return f.func(array, v);
    }
 
    public static void main(String[] args) {
        Integer[] vals = {1, 2, 3, 4, 2, 3, 4, 4, 5};
        String[] strs = {"One", "Two", "Three", "Two"};
 
        //不指定MyFunc型別時,可根據後面的引數推斷
        int count1 = myOp(MyArrayOps::countMatching, vals, 4);
        System.out.println("vals contains " + count1 + " 4s");
 
        //要指定型別時,可以在::後面指定,指定完可以限制後面兩個引數的型別
        int count2 = myOp(MyArrayOps::<String>countMatching, strs, "Two");
        System.out.println("strs contains " + count2 + " Twos");
    }
}