jdk8的新特性有不少,最亮眼的當屬函數式編程的語法糖,本文主要講解下雙冒號::的用法。java
類名::方法名,至關於對這個方法閉包的引用,相似js中的一個function。好比:編程
Function<String,String> func = String::toUpperCase;
(Function在java.util.function包下,也是jdk8新加入的類,同級目錄下有不少函數式編程模型接口,好比Consumer/Predicate/Operator等)閉包
func至關於一個入參和出參都爲String的函數,能夠直接app
func.apply("abc")
接收一個參數,返回一個結果("ABC")。也能夠用於代替下面的Lambda表達式:jvm
List<String> l = Arrays.asList("a","b","c"); l.stream().map(s -> s.toUpperCase()); l.stream().map(func);
下面自定義一個函數式接口ide
public class MyConsumer<String> implements 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 -> {...}
,只有一個參數。this
新建一個類,裏面聲明四個表明各類狀況的方法:code
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);
用::提取的函數,最主要的區別在於靜態與非靜態方法,非靜態方法比靜態方法多一個參數,就是被調用的實例。