jdk8新特性之雙冒號 :: 用法及詳解

jdk8的新特性有很多,最亮眼的當屬函數式編程的語法糖,本文主要講解下雙冒號::的用法。

概念

類名::方法名,相當於對這個方法閉包的引用,類似js中的一個function。比如:

Function<String,String> func =  String::toUpperCase;


(Function在java.util.function包下,也是jdk8新加入的類,同級目錄下有很多函數式編程模型接口,比如Consumer/Predicate/Operator等)


func相當於一個入參和出參都爲String的函數,可以直接

func.apply("abc")


接收一個參數,返回一個結果("ABC")。也可以用於代替下面的Lambda表達式:

List<String> l = Arrays.asList("a","b","c");
l.stream().map(s -> s.toUpperCase());
l.stream().map(func);


下面自定義一個函數式接口

public class MyConsumer<Stringimplements Consumer<String{
    @Override
    public void accept(String s) {
        System.out.println(s);
    }
}


下面這倆種寫法等價:

List<String> l = Arrays.asList("a","b","c");

l.forEach(new MyConsumer<>());
l.forEach(s -> System.out.println(s));


但是,這種寫法卻不行,編譯失敗:

l.forEach(MyConsumer::accept);


因爲MyConsumer的accept方法不是靜態的,如果想使用這個方法,需要一個實例,還需要一個入參,共倆個參數。而List.forEach中需要的是consumer類型,相當於s -> {...},只有一個參數。


下面詳細分析雙冒號使用的各種情況

新建一個類,裏面聲明四個代表各種情況的方法:

public class DoubleColon {

    public static void printStr(String str{
        System.out.println("printStr : " + str);
    }

    public void toUpper(){
        System.out.println("toUpper : " + this.toString());
    }

    public void toLower(String str){
        System.out.println("toLower : " + str);
    }

    public int toInt(String str){
        System.out.println("toInt : " + str);
        return 1;
    }
}


把它們用::提取爲函數,再使用:

Consumer<String> printStrConsumer = DoubleColon::printStr;
printStrConsumer.accept("printStrConsumer");

Consumer<DoubleColon> toUpperConsumer = DoubleColon::toUpper;
toUpperConsumer.accept(new DoubleColon());

BiConsumer<DoubleColon,String> toLowerConsumer = DoubleColon::toLower;
toLowerConsumer.accept(new DoubleColon(),"toLowerConsumer");

BiFunction<DoubleColon,String,Integer> toIntFunction = DoubleColon::toInt;
int i = toIntFunction.apply(new DoubleColon(),"toInt");


非靜態方法的第一個參數爲被調用的對象,後面是入參。靜態方法因爲jvm已有對象,直接接收入參。


再寫一個方法使用提取出來的函數:

public class TestBiConsumer {
    public void test(BiConsumer<DoubleColon,String> consumer){
        System.out.println("do something ...");
    }
}


下面這倆種傳入的函數是一樣的:

TestBiConsumer obj = new TestBiConsumer();
obj.test((x,y) -> System.out.println("do something ..."));
obj.test(DoubleColon::toLower);


總結

用::提取的函數,最主要的區別在於靜態與非靜態方法,非靜態方法比靜態方法多一個參數,就是被調用的實例。


來源:https://my.oschina.net

/wangbo888/blog/1942354


微信圖片_20171210074204.jpg


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章