Lambda的使用與實戰

簡介
(下面的簡介也可以自己百度,一般進來的都是想知道怎麼去用,所以這裏主要也是重點在用法與實戰上)
Lambda表達式是Java SE 8中一個重要的新特性。lambda表達式允許你通過表達式來代替功能接口。 lambda表達式就和方法一樣,它提供了一個正常的參數列表和一個使用這些參數的主體(body,可以是一個表達式或一個代碼塊)。
Lambda表達式還增強了集合庫。 Java SE 8添加了lambda表達式。 在本文中,我們將從簡單到複雜的示例中見認識lambda表達式。
環境準備
如果還沒有安裝Java 8,那麼你應該先安裝才能使用lambda。 像NetBeans 和IntelliJ IDEA 一類的工具和IDE就支持Java 8特性,包括lambda表達式和其他特性。

android studio中使用lambda方法見:  android studio中使用lambda


Lambda表達式的語法
基本語法:
(方法參數) -> 返回值

(方法參數) ->{ 方法內的語句; }

Lambda 簡單與漂亮的案例

 //沒用使用lambda 的代碼
ArrayList<String> strs = new ArrayList<>();
Collections.sort(strs, new Comparator<String>() {
     @Override
     public int compare(String s1, String s2) {
         return s1.compareTo(s2);
    }
});

下面是使用了lambda後的效果

//4行代碼只需要1句代碼就搞定 
Collections.sort(strs, String::compareTo);

Lambda 開始學習

上面的案例在後面會介紹到的.

爲了更好的學習lambda 語法,我自己定義了一些接口,實現內部類,如下:

/**
 * @Des: 內部方法帶1個參數 , 不帶返回值
 */
public interface IParmas1<A> {
    void call(A a);
}
/**
 * @Des: 內部方法帶2個參數 , 不帶返回值
 */
public interface IParmas2<A, B> {
    void call(A a, B b);
}
/**
 * @Des: 內部方法帶2個參數 , 帶返回值
 */
public interface IParmas2AndReturn<A, B, R> {
    R call(A a, B b);
}

設置接口的監聽,實現內部類

 //不帶返回值內部類,1個參數Demo
    public void setOnIParmas1Listener(IParmas1 ipamr) {
    }
    //不帶返回值內部類,2個參數Demo
    public void setOnIParmas2Listener(IParmas2 ipamr) {
    }
    //帶返回值內部類,2個參數Demo
    public void setOnIParmas2AndReturnListener(IParmas2AndReturn ipamr) {
    }
    //配合demo1測試
    public void demo1Test(Object o) {
    }
    //配合demo2測試
    public void demo2Test(Object o1, Object o2) {
    }


Lambda 雙冒號(::)的使用

lambda 還有一個很屌的寫法,看得我都覺得輕飄飄的feel都有了,

 才發現原來java代碼可以這麼單純的,來看看吧,我也是看到這個寫法後才喜歡上lambda的.

那就是 lambda的雙冒號(::)寫法,lambda 雙冒號寫法前提條件是,方法接收的值是參數原值,沒有拼接其他數據,

額,不明白是吧,開始我也是雲裏霧裏,接着看下面解釋吧:

1.這是訂閱IParmas1 接口的一個監聽.

setOnIParmas1Listener(IParmas1 ipamr)

 2.在{@link IParmas1}  接口中定義的方法參數(A a),也就是Object.

void call(A a);

3.因此在接收內部類方法參數,也就是demo1Test(Object o),該方法的參數也是obj 

demo1Test(Object o)
4.這樣條件下就可以直接把下面的,案例1,寫成帶雙冒號lambda 語法了

setOnIParmas1Listener(this::demo1Test);  //(案例1的lambda寫法)

多參數雙冒號寫法,見demo2的案例2.


Demo1 - 雙冒號

//TODO 案例1,方法內部實現使用統一參數類型 原始寫法
setOnIParmas1Listener(new IParmas1() {
    @Override
    public void call(Object o) {
        ParmasImpl.this.demo1Test(o);
    }
});
//lambda 寫法
setOnIParmas1Listener(this::demo1Test);
//TODO 案例2,不帶返回值 原始寫法
setOnIParmas1Listener(new IParmas1() {
    @Override
    public void call(Object s) {
        ParmasImpl.this.demo2();
    }
});
// 不帶返回值的lambda寫法
setOnIParmas1Listener(s -> demo2());

Lambda 匿名內部類的使用

使用lambda 來美化匿名內部類的高度,看起來簡單又優雅

lambda 會直接把整個內部類隱藏,只留下形參,而且有一點要注意,內部類使用lambda,

前提是,該內部類只有一個內部方法,如果有兩個或以上則使用不了lambda語法:

1. 空參數 寫法: () -> 內部類方法的實現.

2. 1參數(String) 寫法: s -> 內部類方法的實現.

需要注意的是當參數爲Void時,寫法與有1個參數的一樣

3. 2個參數(String,int) 寫法: (s,i) -> 內部類方法的實現.

lambda的 內部類寫法與泛型沒有太大關係,但是也要注意器參數是否被引用.

如果引用的話,其實lambda 是不推薦使用表達式的,但是也可以用,就是在用

的時候,他會自動將類型轉換成Object

如寫法1中: s 和 i 現在其實是 obj類型

寫法1:

setOnIParmas2Listener((s, i) -> {
    System.out.println(s + "-----" + i);
});

寫法2:當然也可聲明類型

而且聲明參數類型,只有參數在兩個或以上纔可以,一個參數是不可以聲明的.

setOnIParmas2Listener((Object s,Object  i) -> {
    System.out.println(s + "-----" + i);
});

Demo2 - 匿名內部類

//TODO 案例1: 原始代碼
setOnIParmas2Listener(new IParmas2<String, Integer>() {
    @Override
    public void call(String s, Integer i) {
        System.out.println(s + "-----" + i);
    }
});
//使用lambda 
//因爲上面其實是確定了類型的,被sout引用了,但是如果強制使用lambda的話
//會出現方法參數自動轉向默認obj類型
setOnIParmas2Listener((s,i)-> System.out.println(s + "-----" + i));
//TODO 案例2:多參數使用 lambda雙冒號
setOnIParmas2Listener(new IParmas2() {
    @Override
    public void call(Object o1, Object o2) {
        ParmasImpl.this.demo2Test(o1, o2);
    }
});
//使用lambda
setOnIParmas2Listener(this::demo2Test);

Lambda 方法帶返回值的使用

 在有返回值的時候有兩種情況,下面使用帶兩個參數的內部方法來示範

 1.內部方法直接返回,只有一個實現(方法/語句)

 (s,i) ->  null;

 其實這個寫法就跟返回值是void的一樣,只是void返回值方法內實現一個(方法/語句)而已,

 如demo1的案例2,中的lambda寫法.

 s -> demo2()

 2.內部方法返回, 2個以上實現(方法/語句)

 (s,i) ->  {
 System.out.println("帶了一個sout的實現");
   return null;
 };

Demo2R - 帶返回值

 //TODO 帶返回值的原始方法
setOnIParmas2AndReturnListener(new IParmas2AndReturn<String, Integer, Double>() {
    @Override
    public Double call(String s, Integer i) {
        System.out.println("帶了一個sout的實現");
        return null;
    }
});
//使用lambda 寫法
setOnIParmas2AndReturnListener((s, i) -> {
    System.out.println("帶了一個sout的實現");
    return null;
});


實際代碼中實戰用法

在上面demo 中已經說過了lambda 的一些常用方法,

下面是在實際中 對集合數據排序時的用法:

首先我們分析下Collections.sort(); 功能中參數內部類方法.

內部類Comparator ,默認內部方法compare(s1,s2)參數類型是String,帶返回值int.

這樣我們心裏就大概知道lambda 該怎麼去寫或者這樣寫表達是上面意思.

 //沒用使用lambda 的代碼
ArrayList<String> strs = new ArrayList<>();
Collections.sort(strs, new Comparator<String>() {
    @Override
    public int compare(String s1, String s2) {
        return s1.compareTo(s2);
    }
});
//使用lambda 語法後,簡單好看
/**
 * this::demo1Test 與 String::compareTo 區別
 *
 * 表達的就是當前類下的demo1Test(obj,obj)方法,
 * 其實你如果直接引用compareTo 方法也是可以的,那你就不可以用this了,
 * 而是使用String 對象,因此compareTo 在String 對象內.
 */
// 1.1 使用匿名內部類根據values 排序 strs
Collections.sort(strs, this::demoTest);
// 1.2 使用匿名內部類根據values 排序 strs
Collections.sort(strs, String::compareTo);
// 2 使用lambda根據values  排序 strs
Comparator<String> sortByName = (s1, s2) -> (s1.compareTo(s2));
Collections.sort(strs, sortByName);
// 3 也可以採用聲明形參的寫法:
Collections.sort(strs, (String s1, String s2) -> (s1.compareTo(s2)));

下面是demoTest(String,String)的方法

 /**
 * 提出比較的方法出來,方便lambda的雙冒號寫法調用
 */
private int demo1Test(String s1, String s2) {
    return s1.compareTo(s2);
}

demo代碼:

github

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章