Java8的Lambda表示式你真的會嗎
理解Lambda
Lambda表示式可以是一段可以傳遞的程式碼,它的核心思想是將面向物件中的傳遞資料變成傳遞行為,也就是行為引數化,將不同的行為作為引數傳入方法。
隨著函數語言程式設計思想的引進,Lambda表示式讓可以用更加簡潔流暢的程式碼來代替之前冗餘的Java程式碼。
口說無憑,直接上個例子吧。在Java8之前,關於執行緒程式碼是這樣的:
class Task implements Runnable{ @Override public void run() { System.out.println("Java8 之前 實現Runnable介面中的run方法"); } } Runnable t = new Task();
我們定義了一個Task類,讓它實現Runnable介面,實現僅有的run方法,我們希望執行的執行緒體雖然只有一句話,但我們仍然花了大量大程式碼去定義。為了簡化,我們可以採用匿名內部類的方式:
Runnable taskBeforeJava8 = new Runnable() { @Override public void run() { System.out.println("Java8 之前的寫法,傳入匿名類"); } };
但是,其實還是不夠簡潔,我們用Lambda的寫法是這樣的:
// java8 之後 Runnable taskAfterJava8 = () -> System.out.println("Java8 之後的寫法,lambda表示式");
我們僅僅使用()
和->
就完成了這件事,是不是非常簡潔呢?如果你覺得雖然Lambda寫法簡潔,但是它的規則讓人摸不著頭腦,那就跟著我接下去學叭。
基礎語法
(parameters) -> action (parameters) -> expression (parameters) -> {statements;}
parameters代表變數,可以為空,可以為單,可以為空,你能想到的方式他都可以。
action是實現的程式碼邏輯部分,可以是一行程式碼expression
,也可以是一個程式碼片段statements
。如果是程式碼片段,需要加上{}
。
下面是一些合法的示例,你可以看看有沒有掌握:
表示式 | 描述 |
---|---|
() -> 1024 | 不需要引數,返回值為1024 |
x -> 2 * x | 接收引數x,返回其兩倍 |
(x,y) -> x - y | 接收兩個引數,返回它們的差 |
(int x,int y) -> x + y | 接收兩個int型別引數,返回他們的和 |
(String s) -> print(s) | 接收一個String物件,並列印 |
函式式介面
@FunctionalInterface // 此註解作用的介面 只能擁有一個抽象方法 public interface Runnable { public abstract void run(); }
在這裡,@FunctionalInterface
註解是非必須的,有點類似於@Override
,起強調作用,如果你的介面標註該註解,卻沒有遵循它的原則,編譯器會提示你修改。
常用的函式式介面
JDK原生為我們提供了一些常用的函數語言程式設計介面,讓我們在使用他們程式設計時,不必關心介面名,方法名,引數名,只需關注它的引數型別,引數個數,返回值。
介面 | 引數 | 返回值 | 類別 | 示例 |
---|---|---|---|---|
Consumer | T | void | 消費型介面 | 列印輸出某個值 |
Supplier | None | T | 供給型介面 | 工廠方法獲取一個物件 |
Function | T | R | 函式型介面 | 獲取傳入列表的總和 |
Predicate | T | boolean | 斷言型介面 | 判斷是否以summer為字首 |
消費型介面
@FunctionalInterface // 此註解作用的介面 只能擁有一個抽象方法 public interface Runnable { public abstract void run(); }
供給型介面
/** * 供給型介面,無引數,返回T */ public static void supplierTest() { Supplier<Object> supplier = () -> new Object(); System.out.println(supplier.get()); }
斷言型介面
/** * 斷言型 傳入引數T,返回boolean */ public static void predicateTest() { Predicate<String> predicate = name -> name.startsWith("summer"); System.out.println(predicate.test("summerday")); }
函式型介面
/** * 函式型介面 傳入T 返回R */ public static void functionTest() { List<Integer> list = new ArrayList<>(Arrays.asList(1,2,3,4,5)); Function<List<Integer>,Integer> function = num -> { int res = 0; for (int n : list) { res += n; } return res; }; Integer num = function.apply(list); System.out.println(num); }
方法引用
方法引用可以看作特定Lambda表示式的快捷寫法,主要分為以下兩種:
- 指向靜態方法的方法引用
- 指向現有物件的例項方法的方法引用
/** * 方法引用 * 1. 指向靜態方法的方法引用 * 2. 指向現有物件的例項方法的方法引用 * * @author Summerday */ public class MethodReferenceTest { public static List<String> getList(List<String> params,Predicate<String> filter) { List<String> res = new LinkedList<>(); for (String param : params) { if (filter.test(param)) { res.add(param); } } return res; } // 靜態方法 public static boolean isStartWith(String name) { return name.startsWith("sum"); } public static void main(String[] args) { List<String> params = Arrays.asList("summerday","tqbx","天喬巴夏","summer",""); //靜態方法的方法引用 getList(params,name -> MethodReferenceTest.isStartWith(name)); List<String> list = getList(params,MethodReferenceTest::isStartWith); System.out.println(list); // 指向現有物件的例項方法的方法引用 getList(params,name -> name.isEmpty()); List<String> sum = getList(params,String::isEmpty); System.out.println(sum); } }
陣列引用
/** * 陣列引用 * @author Summerday */ public class ArrayReferenceTest { public static void main(String[] args) { // 普通lambda Function<Integer,String[]> fun1 = x -> new String[x]; String[] res1 = fun1.apply(10); System.out.println(res1.length); // 陣列引用寫法 Function<Integer,String[]> fun2 = String[]::new; String[] res2 = fun2.apply(10); System.out.println(res2.length); } }
構造器引用
/** * 構造器引用 * @author Summerday */ public class ConstructorReferenceTest { public static void main(String[] args) { // 普通lambda Supplier<User> sup = () -> new User(); // 構造器引用 Supplier<User> supplier = User::new; User user = supplier.get(); System.out.println(user); } } class User{ }
總結
- lambda表示式沒有名稱,但有引數列表,函式主體,返回型別,可能還有一個可以丟擲的異常的列表。
- lamda表示式讓你可以將不同的行為作為引數傳入方法。
- 函式式介面是僅僅聲明瞭一個抽象方法的介面。只有在接受函式式介面的地方才可以使用lambda表示式。
- lambda表示式允許你直接內聯,為函式式介面的抽象方法提供實現,並將整個表示式作為函式式介面的一個例項。
- Java8自帶了一些常用的函式式介面,包括
Predicate,Function,Supplier,Consumer,BinaryOperator
。 - 方法引用讓你重複使用現有的方法實現並直接傳遞他們:
Classname::method
。
到此這篇關於Java8的Lambda表示式你真的會嗎的文章就介紹到這了,更多相關Java8的Lambda表示式內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!