Lambda表達(dá)式到底是什么
讓我們從一個(gè)最常用的例子說起芹橡,Java8之前我們循環(huán)一個(gè)List的時(shí)候一般會(huì)這樣寫:
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8);
for(Integer integer : list){
System.out.println(integer);
}
在Java8中我們可以這樣寫:
第一種:
list.forEach(new Consumer<Integer>() {
@Override
public void accept(Integer integer) {
System.out.println(integer);
}
});
是不是看起來好像更繁瑣了呢毒坛,別著急,我們繼續(xù)變化一下:
第二種:
list.forEach(integer -> {System.out.println(integer);});
這里就是使用了Lambda表達(dá)式林说,
我們進(jìn)入forEach
方法的源碼來看一下:
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
方法的參數(shù)是一個(gè)Consumer煎殷,我們來看看這個(gè)Consumer
/**
* @since 1.8
*/
@FunctionalInterface
public interface Consumer<T> {
/**
* Performs this operation on the given argument.
*
* @param t the input argument
*/
void accept(T t);
}
Consumer是Java8開始提供的一個(gè)接口,我們看到這個(gè)接口有一個(gè)注解@FunctionalInterface腿箩,使用這個(gè)注解的接口被稱為“函數(shù)式接口”豪直,我們來看下什么叫函數(shù)式接口:
函數(shù)式接口 FunctionalInterface
1.如果一個(gè)接口只有一個(gè)抽象方法,那么該接口就是一個(gè)函數(shù)式接口
2.如果我們?cè)谀硞€(gè)接口上聲明了FunctionalInterface注解珠移,那么編譯器就會(huì)按照函數(shù)式是接口的要求該接口
3.如果某個(gè)接口只有一個(gè)抽象方法弓乙,但我們并沒有給該接口聲明FunctionalInterface注解末融,那么編譯器依舊會(huì)將該接口看作是函數(shù)式接口
4.Note that instances of functional interfaces can be created with lambda expressions, method references, or constructor references.
一個(gè)函數(shù)式接口的實(shí)例對(duì)象可以使用lambda表達(dá)式、方法引用暇韧、構(gòu)造方法來創(chuàng)建
這里提到了lambda表達(dá)式勾习,這里就解釋了為什么本文一開始第一種寫法到第二種寫法的轉(zhuǎn)變。使用integer -> {System.out.println(integer);}
lambda表達(dá)式來創(chuàng)建Consumer這個(gè)函數(shù)式接口懈玻。
接觸過js之類語言的同學(xué)肯定很眼熟巧婶,在js中函數(shù)參數(shù)是一個(gè)函數(shù),返回值是另一個(gè)函數(shù)是很常見的酪刀,但是在之前的Java中我們無法將函數(shù)作為一個(gè)參數(shù)傳遞給一個(gè)方法,也無法聲明返回一個(gè)函數(shù)的方法钮孵。
為此Java8引入了Lambda表達(dá)式來提供這種方法骂倘,integer -> {System.out.println(integer);}
在這里作為參數(shù),傳遞給 forEach
方法巴席,我們可以把這理解為是一種“行為”历涝,我們是把一種“行為”傳遞給這個(gè)方法,這樣做提升了抽象層次漾唉,使得API重用性更好荧库,更加靈活。
Lambda表達(dá)式的結(jié)構(gòu)
一個(gè)Lambda表達(dá)式主要有以下部分組成:參數(shù)列表赵刑,箭頭(->)分衫,以及一個(gè)表達(dá)式或語句塊。
(arg1,arg2) -> {body}
一個(gè)Lambda表達(dá)式可以有零個(gè)或多個(gè)參數(shù)般此,參數(shù)在圓括號(hào)里蚪战,參數(shù)之間逗號(hào)分隔;
空?qǐng)A括號(hào)代表參數(shù)集為空;
-
當(dāng)只有一個(gè)參數(shù),且其類型可推導(dǎo)時(shí)铐懊,圓括號(hào)()可省略
(x,y) -> {return x + y} () -> {return x + y} x -> x*x
-
參數(shù)的類型既可以明確聲明邀桑,也可以根據(jù)上下文來推斷
不聲明:(x,y) -> {return x+y;} 聲明:(int x,int y) -> {return x+y;}
如果Lambda表達(dá)式的主體只有一條語句,花括號(hào){}可以省略科乎。匿名函數(shù)的返回類型與該主體表達(dá)式一致
-
如果是一條語句以上壁畸,表達(dá)式必須放在華括號(hào){}里(形成代碼塊)
省略前:(int x,int y) -> {return x + y;} 省略后:(int x,int y) -> x + y
常用的Lambda表達(dá)式
- Consumer :
/**
* Consumer
* 接收一個(gè)參數(shù)不返回
* void accept(T t);
*/
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
list.forEach(integer -> { System.out.println(integer); });
- Function:
/**
* Function
* 接收一個(gè)參數(shù),返回一個(gè)值
* R apply(T t);
*/
int result = test.calc(5, value -> value * value); //25
int result2 = test.calc(5, value -> value - 2); //3
public int calc(int a,Function<Integer,Integer> function){
return function.apply(a);
}
3.BiFunction
/**
* BiFunction
* 接收兩個(gè)參數(shù)茅茂,返回一個(gè)值
* R apply(T t, U u);
*/
int result1 = test.calc(3, 4, (a, b) -> a + b);//7
int result2 = test.calc(3, 4, (a, b) -> a * b);//12
public int calc(int a, int b, BiFunction<Integer, Integer, Integer> biFunction) {
return biFunction.apply(a, b);
}
- Comparator
/**
* Comparator
* 接收兩個(gè)參數(shù)捏萍,返回int
* int compare(T o1, T o2);
*/
List<Integer> list = Arrays.asList(6,2, 8, 5, 9, 1, 4, 3);
Collections.sort(list,(a,b) -> a.compareTo(b));
list.forEach(item-> System.out.print(item));//12345689
5.Predicate
/**
* Predicate
* 接收一個(gè)參數(shù),返回布爾值
* boolean test(T t);
*/
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8);
Predicate<Integer> p1 = value -> value % 2 == 0;
Predicate<Integer> p2 = value -> value > 5;
list.stream().filter(p1).collect(Collectors.toList()).forEach(item -> System.out.print(item));//2468
list.stream().filter(p1.and(p2)).collect(Collectors.toList()).forEach(item -> System.out.print(item));//68
6.Supplier
/**
* Supplier
* 不接收參數(shù)返回一個(gè)值
* T get();
*/
Supplier<Student> supplier = () -> new Student();
Student student = supplier.get();