天天看點

Java8新特性之方法引用

一、概述

1. 引入

方法引用是在Java8中引入的新特性,使用方法引用可以進一步的簡化Lambda的一些基本操作。我們知道在JavaScript中方法也是對象,也就是說,我們可以直接對方法進行傳遞,方法可以作為某個函數的參數。Java的方法引用也是類似的思想,使用方法引用可以對方法的引用進行傳遞,然後由接受的方法底層進行執行。

方法引用使用的一般方式如下:

List<String> list = Arrays.asList("A","B","C");
list.forEach(System.out::println);
           

在使用Lambda表達式時我們一般這樣使用:

list.forEach((e) -> System.out.println(e));
           

在使用匿名内部類時,我們通常這樣使用:

list.forEach(new Consumer<String>() {
    @Override
    public void accept(String s) {
        System.out.println(s);
    }
});
           

2. 總結

根據上面引入部分的内容我們可以看出,方法引用比Lambda表達式使用起來更為友善,當時并不是所有的場景都适合使用方法引用。想要使用方法引用需要符合以下條件:

引用的方法的參數和傳回值類型和Lambda表達式使用的函數式接口中的抽象方法的參數和傳回值相同。
           

我們可以分析一下上面的例子:

list.forEach(System.out::println);
//System.out表示的是一個對象,而println是其中的一個執行個體方法。在這裡表示引用System.out對象中的println方法
//而println方法有一個參數,類型是String,沒有傳回值
           
new Consumer<String>() {
    @Override
    public void accept(String s) {
        System.out.println(s);
    }
}
//上述内容表示一個消費型的函數式接口,它裡面有一個抽象方法,accept,有一個參數,類型為String
//沒有傳回值
           

可以看出,在使用方法引用方式時

println

方法的參數類型數量以及傳回值類型和函數式接口

Consumer

中的

accept

方法的參數類型數量和傳回值類型都是一樣的。是以在這裡可以使用方法引用。

二、構造方法引用

1. 使用

在接口新特性中,我們講到,Java8中的函數式接口有一種供給型接口

Supplier

。我們可以使用這個接口來完成建立對象的過程。

Supplier<Object> supplier1 = new Supplier<Object>() {
    @Override
    public Object get() {
        return new Object();
    }
};
           

但是這個過程很複雜,後來我們可以使用Lambda表達式來完成這個過程。

Supplier<Object> supplier2 = () -> new Object();
           

使用方法引用之後,我們可以直接這樣寫

Supplier<Object> supplier3 = Object::new;
System.out.println(supplier3.get());
           

2. 注意

通過上面的案例我們需要再次明确:

方法引用的使用是在被引用的方法參數,傳回值資訊和函數式接口中抽象方法的參數,傳回值等資訊相同的情況下使用

比如說在使用構造方法引用時如果沒有無參構造器,就沒辦法使用

Supplier

接口來實作方法引用。

三、類方法(靜态方法)引用

在接口新特性中我們講到Java8中有一個函數式接口是函數式

Function

,我們通過這個接口可以完成很多的事情。

例如,将String類型的字元串轉換為Int類型

Function<String,Integer> function2 = new Function<String, Integer>() {
    @Override
    public Integer apply(String s) {
        return Integer.parseInt(s);
    }
};
           

同時我們還可以使用Lambda表達式的方式

Function<String,Integer> function = (s) -> Integer.parseInt(s);
           

使用方法引用的方式

Function<String,Integer> function1 = Integer::parseInt;
           

還有就是比較兩個Integer類型的值的大小

傳統的方式

Comparator<Integer> comparator = new Comparator<Integer>() {
    @Override
    public int compare(Integer o1, Integer o2) {
        return Integer.compare(o1, o2);
    }
};
           

Lambda表達式方式

Comparator<Integer> comparator1 = ((o1, o2) -> Integer.compare(o1, o2));
           

方法引用方式

Comparator<Integer> comparator2 = Integer::compareTo;
           

四、類執行個體方法引用

1. 案例

對字元串數組中的元素進行排序。

傳統方式

Arrays.sort(strings, new Comparator<String>() {
    @Override
    public int compare(String o1, String o2) {
        return o1.compareTo(o2);
    }
});
           
Arrays.sort(strings,(a,b) -> a.compareTo(b));
           
Arrays.sort(strings,String::compareTo);
           

五、對象執行個體方法引用

統計List集合的容量

List<String> list = Arrays.asList("1","2","3");
Supplier<Integer> supplier = new Supplier<Integer>() {
    @Override
    public Integer get() {
        return list.size();
    }
};
           

Lambda表達式

Supplier<Integer> supplier1 = () -> list.size();
           

對象執行個體方法引用

Supplier<Integer> supplier2 = list::size;
           

如果不使用對象執行個體方法方式,也可以這樣

//Lambda表達式
Function<List<?>,Integer> function = (e) -> e.size();
//方法引用方式
function = List::size;