文章目錄
- 1. 介紹
- 2. Lambda 運算式的語法
- 3. 函式介面
- 4. Lamdba 運算式的使用
- 5. 變數捕獲
- 5.1 介紹
- 5.2 匿名內部類的變數捕獲
- 5.3 Lambda 的變數捕獲
- 6. Lambda 在集合中的使用
- 6.1 Collection 介面
- 6.2 List 介面
- 6.3 Map 介面
- 7. Lambda 運算式的優點和缺點
1. 介紹
- Lambda 運算式是 JavaSE8 中的一個重要的新特性
- Lambda 運算式允許你通過運算式來代替功能介面
- Lambda 運算式和方法一樣,它提供了一個正常的引數串列和一個使用這些引數的主體
- Lambda 運算式可以看作是一個匿名函式,基于數學中的 λ 演算得名,也可以稱其為閉包
- Lambda 運算式允許把函式作為一個方法的引數
2. Lambda 運算式的語法
基本形式: Lambda 運算式由三部分組成:引數、->符號、方法體
(引數串列)->{方法體}
補充:
- Lambda 運算式的引數可以是零個或多個
- 引數的型別可以明確宣告,也可以不宣告,由 JVM 隱式的推斷,例如
(int a)和(a)效果相同- 當引數只有一個,且型別可推導時,可以省略括號,例如
(a)與a效果相同- 如果 Lambda 運算式的方法體只有一條陳述句時,可以省略花括號
- 如果 Lambda 運算式的方法體只有一條陳述句,且為回傳值的時候,可以省略 return
代碼示例:
// 不需要引數,回傳值為 2
()->2
// 接收一個引數(數字型別),回傳值為其2倍的值
x->2*x
// 接收兩個引數(數字型別),并回傳它們的和
(x,y)->x+y
// 接收兩個 int 型別引數,回傳它們的乘積
(int x,int y)->x*y
// 接收一個 String 物件,并在控制臺列印
(String s)->System.out.println(s)
3. 函式介面
如果一個介面中有且只有一個 abstract 方法,稱這樣的介面為單介面,從 JDK8 開始,Java 使用 Lambda 運算式,并將單介面稱為函式介面
注意:
- 如果一個介面只有一個抽象方法,那么該介面就是一個函式式介面
- 如果我們在某個介面上宣告了
@FunctionInterface注解,那么編譯器就會按照函式式介面的定義來要求該介面,因此這個介面只能有一個抽象方法,如果超過,程式編譯時就會報錯
示例代碼:
@functionInterface
interface A{
void test();
}
4. Lamdba 運算式的使用
接下來為大家演示 Lambda 運算式的使用
// 無回傳值無引數
@FunctionalInterface interface NoParameterNoReturn { void test(); }
// 無回傳值一個引數
@FunctionalInterface interface OneParameterNoReturn { void test(int a); }
// 無回傳值多個引數
@FunctionalInterface interface MoreParameterNoReturn { void test(int a,int b); }
// 有回傳值無引數
@FunctionalInterface interface NoParameterReturn { int test(); }
// 有回傳值一個引數
@FunctionalInterface interface OneParameterReturn { int test(int a); }
// 有回傳值多引數
@FunctionalInterface interface MoreParameterReturn { int test(int a,int b); }
public class TestDemo {
public static void main(String[] args) {
NoParameterNoReturn noParameterNoReturn = ()->{ System.out.println("無引數無回傳值"); };
noParameterNoReturn.test();
OneParameterNoReturn oneParameterNoReturn = (int a)->{ System.out.println("無引數一個回傳值:"+ a); };
oneParameterNoReturn.test(10);
MoreParameterNoReturn moreParameterNoReturn = (int a,int b)->{ System.out.println("無回傳值多個引數:"+a+" "+b); };
moreParameterNoReturn.test(20,30);
NoParameterReturn noParameterReturn = ()->{ System.out.println("有回傳值無引數!"); return 40; };
//接收函式的回傳值
int ret = noParameterReturn.test();
System.out.println(ret);
OneParameterReturn oneParameterReturn = (int a)->{ System.out.println("有回傳值有引數!"); return a; };
ret = oneParameterReturn.test(50);
System.out.println(ret);
MoreParameterReturn moreParameterReturn = (int a,int b)->{ System.out.println("有回傳值多個引數!"); return a+b; };
ret = moreParameterReturn.test(60,70);
System.out.println(ret);
}
}
5. 變數捕獲
5.1 介紹
Java 中的區域類和匿名類都存在變數捕獲
只有理解了什么是變數捕獲之后,我們才能更好地理解 Lambda 運算式的作用域,因為 Lambda 運算式也存在變數捕獲,
5.2 匿名內部類的變數捕獲
class A {
public void func(){
System.out.println("func()");
}
}
public class TestDemo {
public static void main(String[] args) {
int a = 100;
new Test(){
@Override public void func() {
System.out.println("我是內部類,且重寫了func這個方法!");
System.out.println("我是捕獲到變數 a == "+a +" 我是一個常量,或者是一個沒有改變過值的變數!");
}
};
}
}
上述代碼中的變數 a 就是捕獲變數,這個變數要么是被 final 修飾,要么就要保證此變數在匿名內部類中使用時沒有被修改,如果修改就會編譯出錯
5.3 Lambda 的變數捕獲
在 Lambda 中也可以進行變數捕獲
@FunctionalInterface interface A {
void test();
}
public static void main(String[] args) {
int a = 10;
NoParameterNoReturn noParameterNoReturn = ()->{
// a = 99; 如果修改a,則會報錯
System.out.println("捕獲變數:"+a);
};
noParameterNoReturn.test();
}
6. Lambda 在集合中的使用
為了能夠讓 Lambda 和 Java 的集合類集更好的一起使用,集合當中也新增了部分介面,以便與 Lambda 運算式對接
| 對應的介面 | 新增的方法 |
|---|---|
| Collection | removeIf()、spliterator()、stream()、parallelStream()、forEach() |
| List | replaceAll()、sort() |
| Map | getDefault()、forEach()、replaceAll()、putIfAbsent()、remove()、replace()、computeIfAbsent()、computeIfPresent()、compute()、merge() |
補充:
Collection 的
forEach()方法是從介面java.lang.Interable繼承的
6.1 Collection 介面
使用 forEach() 方法進行演示
forEach() 原始碼: 
代碼示例: 使用匿名內部類
public class TestDemo{
public static void main(String[] args) {
List<String> list=new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.forEach(new Consumer<String>() {
@Override
public void accept(String s) {
System.out.print(s+" ");
}
});
}
}
// 結果為:aaa bbb ccc
代碼示例: 使用 Lambda
public class TestDemo{
public static void main(String[] args) {
List<String> list=new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.forEach(s -> System.out.print(s+" "));
}
}
// 結果為:aaa bbb ccc
6.2 List 介面
使用 sort() 方法進行演示
sort() 原始碼: 
代碼示例: 使用匿名內部類
public class TestDemo{
public static void main(String[] args) {
List<String> list=new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.sort(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
System.out.println(list);
}
}
// 結果為:[aaa, bbb, ccc]
代碼示例: 使用 Lambda
public class TestDemo{
public static void main(String[] args) {
List<String> list=new ArrayList<>();
list.add("aaa");
list.add("bbb");
list.add("ccc");
list.sort((String o1,String o2)->o1.compareTo(o2));
System.out.println(list);
}
}
// 結果為:[aaa, bbb, ccc]
6.3 Map 介面
使用 HashMap 的 forEach() 方法進行演示
HashMap 的 forEach() 原始碼:

代碼示例: 使用匿名內部類
public class TestDemo{
public static void main(String[] args) {
Map<Integer,String> map=new HashMap<>();
map.put(1,"aaa");
map.put(2,"222");
map.put(3,"333");
map.forEach(new BiConsumer<Integer, String>() {
@Override
public void accept(Integer integer, String s) {
System.out.println("Key="+integer+" Value="+s);
}
});
}
}
/** 結果為:
Key=1 Value=aaa
Key=2 Value=222
Key=3 Value=333
*/
代碼示例: 使用 Lambda
public class TestDemo{
public static void main(String[] args) {
Map<Integer,String> map=new HashMap<>();
map.put(1,"aaa");
map.put(2,"222");
map.put(3,"333");
map.forEach((Integer integer,String s)->
System.out.println("Key="+integer+" Value="+s));
}
}
/** 結果為:
Key=1 Value=aaa
Key=2 Value=222
Key=3 Value=333
*/
7. Lambda 運算式的優點和缺點
優點:
- 代碼簡潔,開發迅速
- 方便函式式編程
- 容易進行并行計算
- Java 引入 Lambda,改善了集合操作
缺點:
- 代碼可讀性變差
- 在非并行計算中,很多計算未必有傳統 for 回圈性能高
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/389221.html
標籤:其他
