Lambda表達(dá)式
Lambda是一個(gè)匿名函數(shù),我們可以把Lambda表達(dá)式理解為是一段可以傳遞的代碼(將代碼像數(shù)據(jù)一樣進(jìn)行傳遞),其可以代替實(shí)現(xiàn)接口中的抽象方法時(shí)的書寫匿名內(nèi)部類的繁瑣代碼。
舉個(gè)栗子:
Java中有個(gè)Runnable接口,直接使用該接口,需要重寫實(shí)現(xiàn)其接口內(nèi)部中的抽象方法。如下:
Runnable run = new Runnable() {
@Override
public void run() {
System.out.println("old run");
}
};
run.run();
該代碼可以使用lambda表達(dá)式簡化為:
Runnable run1 = () -> System.out.println("lambda run");
run1.run();
1. 基礎(chǔ)語法
java8中引入了一個(gè)新的操作符 ->,該操作符稱為箭頭操作符或Lambda操作符,該箭頭符號將整個(gè)Lambda表達(dá)式拆分成兩部分:
左側(cè):Lambda表達(dá)式的參數(shù)列表,即接口中對應(yīng)抽象方法的參數(shù)列表。
右側(cè):Lambda表達(dá)式中所需要執(zhí)行的功能,即Lambda表達(dá)式體。即需要實(shí)現(xiàn)的抽象方法的功能體。
1.1. 語法格式一 無參數(shù),無返回值
對應(yīng)格式為: () -> 方法體... 括號內(nèi)無參數(shù)
例如:() -> Sysout...
@Test
public void test1 (){
//無參數(shù) , 無返回值 對應(yīng)格式為: () -> 方法體... 括號內(nèi)無參數(shù)
Runnable run = new Runnable() {
@Override
public void run() {
System.out.println("old run");
}
};
run.run();
System.out.println("-----------");
Runnable run1 = () -> System.out.println("lambda run");
run1.run();
}
/*result:
old run
-----------
lambda run
*/
1.2. 語法格式二 有一個(gè)參數(shù),無返回值
對應(yīng)語法格式為 (x) -> 無返回值的方法體
例如: (x) -> System.out.println(x)
若有且只有一個(gè)參數(shù),左側(cè)的小括號可以省略不寫
例如: x -> System.out.println(x)
// 有一個(gè)參數(shù) , 無返回值
@Test
public void test2(){
List<String> list = new ArrayList<>();
Consumer<String> consumer = (s) -> list.add(s);//將consumer接收到的對象進(jìn)行具體的功能的消費(fèi)
consumer.accept("ddd");
consumer.accept("aaa");
consumer.accept("ccc");
list.forEach(System.out::println);
/*
Result:
ddd
aaa
ccc
*/
}
1.3. 語法格式三 有兩個(gè)或兩個(gè)以上參數(shù),有返回值
有
兩個(gè)或兩個(gè)以上參數(shù),有返回值,并且 lambda體中有多條語句
語法為:
(x,y) -> {
方法體
return 返回值
}
多條語句必須使用大括號包括在內(nèi),
有返回值,需要使用return 返回返回值.
Comparator<Integer> com = (x, y) -> {
System.out.println("x為"+x);
System.out.println("y為"+y);
return Integer.compare(x,y);
};
如果lambda體中只有一條語句,
那么大括號{}可以省略,
return關(guān)鍵字也可以省略
例如:
Comparator<Integer> com = (x,y) -> {
return Integer.compare(x,y);
}
就可以簡寫成:
Comparator<Integer> com = (x,y) -> Integer.compare(x,y);
Lambda表達(dá)式的參數(shù)列表的 數(shù)據(jù)類型可以省略不寫,
因?yàn)镴VM編譯器可以通過上下文推斷出數(shù)據(jù)類型,即'類型推斷'.
即:
(Integer x,Integer y) -> Integer.compare(x,y);
簡化成:
(x,y) -> Integer.compare(x,y);
@Test
public void test3(){
Comparator<Integer> com = (x, y) -> {
System.out.println("x為"+x);
System.out.println("y為"+y);
return Integer.compare(x,y);
};
System.out.println(com.compare(1111,111));
// x為1111
// y為111
// 1
}
利用用Java內(nèi)置的Comparator接口(比較器)比較兩個(gè)字符串的長度,可用lambda表達(dá)式表示為:
使用Lambda表達(dá)式直接進(jìn)行該接口的核心方法體的重寫
//使用Lambda表達(dá)式直接進(jìn)行該接口的核心方法體的重寫
Comparator<String> com1 = (x,y) -> {
if(x.length() == y.length()){
return 0;
}else{
if(x.length() > y.length()){
return 1;
}else
return -1;
}
};
System.out.println(com1.compare("aa","aaaaa"));// -1
2. 函數(shù)式接口
Lambda表達(dá)式需要
函數(shù)式接口的支持函數(shù)式接口定義: 接口中
只有一個(gè)抽象方法的接口,稱為函數(shù)式接口。可以使用注解
@FuncitonalInterface修飾,其修飾作用為:限定該接口必須為函數(shù)式接口,即該接口中有且只有一個(gè)抽象方法。否則無法通過編譯。即可以檢查是否為函數(shù)式接口。
2.1. 自定義一個(gè)函數(shù)式接口:
@FunctionalInterface
public interface Operation<T,R> {
public R operation(T t1, T t2);
}
2.1.1 方案一:寫具體實(shí)現(xiàn)方法再直接使用
public void op (Long l1, Long l2, Operation<Long,Long> operation){
System.out.println(operation.operation(l1,l2));
}
@Test
public void testMyOperation(){
op(10l,10l,(x,y) -> x*y);//100
op(100l,200l,(x,y)-> x+y);//300
}
2.1.2 方案二: 先使用lambda表示具體實(shí)現(xiàn)方法體,再進(jìn)行接口中的方法調(diào)用,傳入具體值:
@Test
public void testMyOperation(){
Operation<Integer,Integer> op = (x,y) -> x*y;
System.out.println(op.operation(10,10)); //100
}
實(shí)際使用時(shí),大多數(shù)情況下直接使用
Java8內(nèi)置四大函數(shù)式接口,并不要進(jìn)行自己寫函數(shù)式接口。
3. Java內(nèi)置的四大核心函數(shù)式接口
Consumer<T> 消費(fèi)型接口 消費(fèi)對象
void accept(T t);
Supplier<T> 供給型接口 生成對象
T get();
Function<R,T> 函數(shù)型接口 指定特定功能
R apply(T t);
Predicate<T> 斷言型接口 進(jìn)行條件判斷
boolean test(T t);
3.1. 消費(fèi)型接口
Consumer<T>消費(fèi)型接口
void accept(T t);
// Consumer<T> 消費(fèi)型接口
@Test
public void testConsumer(){
//此時(shí)的(d) 小括號里有參數(shù)
//原因是因?yàn)?Consumer接口有參數(shù)
//void accept(T t);
consume(1000,(d)-> System.out.println(d));
}
public void consume(Integer n , Consumer<Integer> con){
//函數(shù)接口接收 消費(fèi) 形參n
con.accept(n);
}
3.2. 供給型接口
Supplier<T>供給型接口
T get();小括號無參數(shù)
// Supplier<T> 供給型接口
@Test
public void testSupplier(){
//T get(); 小括號無參數(shù)
List<Integer> numList = getNumList(10,() -> (int)(Math.random()*101));
for ( Integer i: numList
) {
System.out.println(i);
}
}
//調(diào)用此方法時(shí),第二個(gè)參數(shù)提供一個(gè)數(shù)字集合
public List<Integer> getNumList(int n, Supplier<Integer> sup){
List<Integer> numList = new ArrayList<>();
for (int i = 0; i < n; i++){
numList.add(sup.get()); //通過get方法得到數(shù)字 存到numList
}
return numList;
}
3.3. 函數(shù)型接口
Function<R,T>函數(shù)型接口指定特定功能
//Function<R,T> 函數(shù)型接口 特定功能
@Test
public void testFunction(){
//將字符串轉(zhuǎn)成大寫
String str1 = strHandler("ghslkajh", (s) -> s.toUpperCase());
System.out.println(str1);
}
// Function<R,T> 函數(shù)型接口
//定義一個(gè)處理字符串功能型接口函數(shù)
public String strHandler(String str, Function<String,String> fun){
return fun.apply(str);
}
3.4. 斷言型接口
Predicate<T>條件判斷
boolean test(T t);返回boolean
//斷言型接口 Predicate<T>
// boolean test(T t); 返回boolean
@Test
public void testPredicate(){
//返回長度大于3的字符串
List<String> s1 = strFilter(Arrays.asList("huzhiqi", "adaad", "1231", "414441", "gagsgasg"), (s) -> s.length() > 3);
System.out.println(s1); //[huzhiqi, adaad, 1231, 414441, gagsgasg]
//返回包含d的字符串
List<String> s2 = strFilter(Arrays.asList("huzhiqi", "adaad", "1231", "414441", "gagsgasg"), (s) -> s.contains("d"));
System.out.println(s2); // [adaad]
}
//使用斷言型接口過濾字符串
public List<String> strFilter(List<String> strs, Predicate<String> pred){
List<String> list = new ArrayList<>();
for (String s:strs
) {
//利用斷言型接口進(jìn)行指定功能判斷 即一個(gè)功能性條件判斷
if(pred.test(s)){
//過濾功能
list.add(s);
}
}
return list;
}