初識lambda表達式
lambda表達式是Java8的新特性,可以將lambda表達式看成是精簡語法的匿名內(nèi)部類汰寓。
舉個例子口柳,一般的匿名類處理如下
// 為button注冊一個事件
button.setOnAction(
new EventHandler<ActionEvent>(){
@Override
public void handle(ActionEvent e){
// do something
}
}
);
如果使用lambda表達式,代碼可以得到極大地簡化有滑,如下所示:
button.setOnAction( (e) ->{
//do something
}
);
為了更好地理解lambda表達式跃闹,我們先引入函數(shù)式接口的概念。
函數(shù)式接口(functional interface)
簡單地說毛好,接口中若只包含一個抽象方法望艺,則稱該接口為函數(shù)式接口〖》茫可以在接口前使用注解@FunctionalInterface
檢查該接口是否為函數(shù)式接口找默。
lambda表達式基本語法
在Java8中,引入了一個新的操作符"->",該操作符將lambda表達式拆分成兩個部分:
- lambda表達式的參數(shù)列表吼驶,位于"->"操作符左邊
- lambda表達式所執(zhí)行的功能啡莉,即lambda體。位于"->"操作符右邊旨剥。
一個lambda表達式的基礎語法是
(type1 param1, type2 param2, ...)->{
statements;
}
編譯器對待一個lambda表達式就如同它是從一個匿名內(nèi)部類創(chuàng)建的對象咧欣。
簡單來說,lambda表達式的參數(shù)列表就是函數(shù)式接口中抽象方法的參數(shù)列表轨帜,lambda體就是該方法的方法體魄咕。
以本文開頭的代碼為例,EventHandler接口僅有一個方法蚌父,并且該方法具有一個ActionEvent類型的參數(shù)哮兰,所以編譯器可以自動推斷出e是一個ActionEvent類型的參數(shù),并且花括號里面的內(nèi)容為handle方法的方法體苟弛。
如果EventHandler接口中含有多個方法喝滞,編譯器將無法編譯lambda表達式,可以看出膏秫,lambda表達式是根據(jù)編譯器的隱式推斷來簡化代碼的右遭。所以,==lambda表達式需要函數(shù)式接口的支持==。
明白了lambda表達式的運行機制窘哈,下面就是常見的lambda表達式的語法格式:
-
函數(shù)式接口中的方法無參數(shù)吹榴,例子如下:
() ->{//do something}
若方法體只有一個語句,return和花括號都可以省略不寫滚婉。
-
函數(shù)式接口中的方法有參數(shù)图筹,例子如下:
(int x, int y)
-> {//do something}表達式中參數(shù)的類型可以不寫,編譯器可以通過上下文推斷出其類型让腹,上面的代碼可以簡化如下:
(x, y) ->{do something}
如果只有一個參數(shù)远剩,參數(shù)列表的括號可以省略,例子如下:
x ->{//do something}
四大核心函數(shù)式接口
寫lambda表達式需要有函數(shù)式接口支持骇窍,單并不是說每次用lambda表達式時都要自定義一個函數(shù)式接口民宿,實際上,Java8已經(jīng)為我們準備了java.util.function包像鸡,其中有許多非常實用的函數(shù)式接口活鹰,大致可以分為4種,下面介紹4種核心的接口的典型代表只估。
消費型接口
消費型接口典型的代表為Consumer志群,其抽象方法為accept(), 該方法僅接受一個參數(shù),并且沒有返回值蛔钙。示例如下:
//打印字符串
public static void main(String[] args) {
handle("Hello world!", (s) -> System.out.println(s));
}
public static void handle(String s, Consumer<String> con) {
con.accept(s);
}
供給型接口
供給型接口的典型代表為Supplier锌云,其抽象方法為get(), 該方法不接受參數(shù),但有返回值吁脱。示例如下:
public static void main(String[] args) {
List<Integer> list = getNumList(10, () -> (int)(Math.random() *100));
for(Integer i:list) {
System.out.println(i);
}
}
//產(chǎn)生指定個數(shù)的整數(shù)桑涎,并將其置于集合中
public static List<Integer> getNumList(int num, Supplier<Integer> sup){
List<Integer> list = new ArrayList<>();
for(int i = 0; i < num; i++) {
list.add(sup.get());
}
return list;
}
函數(shù)型接口
函數(shù)型接口中的代表為Function,其抽象方法位apply(), 接受有一個參數(shù)兼贡,并且有返回值攻冷。示例如下:
//將字符串轉(zhuǎn)化為整型
public static void main(String[] args) {
System.out.println(convert("100", (e) -> Integer.parseInt(e)));
}
public static Integer convert(String str, Function<String, Integer> fun) {
return fun.apply(str);
}
斷言型接口
斷言型接口的典型接口為Predicate,其抽象方法為test(), 接受一個參數(shù)遍希,并返回一個布爾值等曼。示例如下:
// 將滿足條件的整數(shù)放于集合中
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3, 5, 7, 11, 20, 47);
List<Integer> myList = filterInt(list, (e) -> e > 3);
for(Integer i : myList) {
System.out.println(i);
}
}
public static List<Integer> filterInt(List<Integer> list, Predicate<Integer> pre ){
List<Integer> myList = new ArrayList<>();
for(Integer i : list) {
if(pre.test(i)) {
myList.add(i);
}
}
return myList;
}