Lambda表達式
Lambda 表達式是 JDK1.8 的一個新特性,又稱特殊的匿名內部類,可以取代大部分的匿名內部類,語法更簡潔,可以寫出更優雅的 Java 代碼,可以極大地優化代碼結構。
Lambda 表達式不會生成單獨的內部類文件,但匿名內部類會。
Lambda表達式特性
★ Lambda 表達式沒有顯示的方法名。
★ Lambda 表達式很像一個函數,具有參數列表、函數體、返回類型、異常,但沒有函數名。
★ Lambda 表達式可以作為方法的參數,也可以作為變量存儲。
★ Lambda 表達式的代碼更加簡潔和精確。
Lambda表達式的定義
基本語法:
<函數式接口> <變量名> = (參數1, 參數2...) -> {
//方法體
};
或
<函數式接口> <變量名> = (參數1, 參數2...) -> 表達式;
注意事項:
✔ Lambda 表達式由三部分構成:參數列表、箭頭(->)、Lambda 體。
✔ Lambda 體,可以是一個表達式,也可以是一個語句塊。
✔ Lambda 體,表達式中不能加入 return 語句,因為在表達式中已經隱含了 return 語句;但是,語句塊中沒有隱含,需要使用 return 語句。
✔ Lambda 表達式並不是對所有接口都可以實現,接口需要滿足一個條件才能被Lambda 表達式實現:Lambda 規定接口中只能有一個需要被實現的方法。注意,並不是規定接口中只能有一個方法。
特別提醒:
jdk1.8 中的另一個新特性:default,被 default 修飾的方法會有默認實現,不是必須被實現的方法。在實現Lambda 表達式的時候需注意。
Lambda 表達式的使用
1.無參,有返回值
@FunctionalInterface public interface LambdaTest { // 無參,有返回值
int method(); }
public class test { public static void main(String[] args) { LambdaTest test = ()-> 20; int result = test.method(); System.out.println(result); } }
@FunctionalInterface注解:
修飾函數式接口的,要求接口中的抽象方法只有一個。這個注解往往和 lambda 表達式一起出現。
2.無參,無返回值
@FunctionalInterface public interface LambdaTest { // 無參,無返回值
void method(); }
public class test { public static void main(String[] args) { LambdaTest test = () -> {}; test.method(); } }
3.單參,有返回值
@FunctionalInterface public interface LambdaTest { // 單參,有返回值
int method(int a); }
public class test { public static void main(String[] args) { // 表達式形式
LambdaTest test = a -> a+10; System.out.println(test.method(10)); // 代碼塊形式
LambdaTest test2 = a -> { return a+10; }; System.out.println(test2.method(10)); } }
4.多參,有返回值
@FunctionalInterface public interface LambdaTest { // 多參,有返回值
int method(String a, String b); }
public class test { public static void main(String[] args) { // 表達式形式
LambdaTest test = (a, b) -> a.length() - b.length(); System.out.println(test.method("abb", "bbccdd")); // 代碼塊形式
LambdaTest test2 = (a, b) -> { return a.length() - b.length(); }; System.out.println(test2.method("abb", "bbccdd")); } }
表達式使用技巧總結
★ 形參列表的數據類型會自動判斷。
★ 如果形參列表為空,只需保留()。
★ 如果形參只有一個,()可以省略,只需要參數的名稱即可。
★ 如果執行語句只有一句,且無返回值,則{}可省略;如果有返回值,若想省略{},則必須同時省略return,且執行語句也必須保證只有一句。
Lambda 表達式應用
方法引用
有時候我們不是必須要自己重寫某個匿名內部類的方法,我們可以可以利用 lambda表達式的接口快速指向一個已經被實現的方法。
引用語法:
方法歸屬者::方法名
靜態方法的歸屬者為類名,普通方法歸屬者為對象。
常見形式:
對象 :: 實例方法
類 :: 靜態方法
類 :: 實例方法
類 :: new
引用要求:
① 參數數量和類型要與接口中定義的一致。
② 返回值類型要與接口中定義的一致。
代碼示例:
public class MethodReferences { public static void main(String[] args) { // 1.對象::實例方法
Consumer<String> consumer = s->System.out.println(s); consumer.accept("hello"); Consumer<String> consumer2 = System.out::println; consumer2.accept("world"); // 2.類::靜態方法
Comparator<Integer> com = (o1, o2)->Integer.compare(o1, o2); Comparator<Integer> com2 = Integer::compare; // 3.類::實例方法
Function<String, String> function = e->e.toUpperCase(); Function<String, String> function2 = String::toUpperCase; System.out.println(function2.apply("hello")); // 4.類::new
Supplier<String> supplier = ()->new String(); Supplier<String> supplier2 = String::new; System.out.println(supplier2.toString()); } }
創建線程
public class TestLambda { public static void main(String[] args) { // 匿名內部類
Runnable runnable = new Runnable() { @Override public void run() { System.out.println("子程序執行。。。"); } }; // Lambda表達式
Runnable runnable2 = ()->System.out.println("子程序執行2。。。"); new Thread(runnable2).start();
new Thread(()->System.out.println("子程序執行3。。。")).start(); } }
集合操作
可以調用集合的 public void forEach(Consumer<? super E> action)
方法,通過 Lambda 表達式的方式遍歷集合中的元素。Consumer 接口是 jdk 為我們提供的一個函數式接口。
public class test { // 集合遍歷
public static void main(String[] args) { ArrayList<Integer> list = new ArrayList<>(); Collections.addAll(list, 4, 3, 9, 0, 5); // 方法引用
list.forEach(System.out::println); // Lambda表達式
list.forEach(element -> { if (element % 2 == 0) { System.out.println(element); } }); } }
public class test { // 集合排序
public static void main(String[] args) { ArrayList<Integer> list = new ArrayList<>(); Collections.addAll(list, 4, 3, 9, 0, 5); // 匿名內部類
list.sort(new Comparator<Integer>() { @Override public int compare(Integer o1, Integer o2) { return o1 - o2; } }); // lambda表達式
list.sort((o1,o2)->o1-o2); list.forEach(System.out::println); } }