Android 使用jdk1.8新特性之lambda表達式

目前Java 8的新特性Lambda 結合 RxJava 在一起使用可以簡化大量的代碼,下面簡單介紹在AndroidStudio中配置Gradle使得支持Java 8。

Android 使用Java8 配置

添加插件retrolambda

在project層的build.gradle配置

buildscript {
    repositories {
        jcenter()
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.2.0'
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
        classpath 'me.tatarka:gradle-retrolambda:3.2.5' //添加插件retrolambda
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

配置android{}區塊Jav//java版本8

compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}

配置完成之後的build.gradle文件

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'me.tatarka:gradle-retrolambda:3.2.4' //for java 8 lamda
    }

}

apply plugin: 'com.android.application'
apply plugin: 'me.tatarka.retrolambda'

android {

    compileSdkVersion 23
    buildToolsVersion "23.0.1"

    defaultConfig {
        applicationId "com.mrljdx.sample"
        minSdkVersion 10
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }

    //java版本8
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    .....//省略其他配置

}

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    testCompile 'junit:junit:4.12'
    //java 8 配置
    retrolambdaConfig 'net.orfjackal.retrolambda:retrolambda:+'
}

配置proguard.pro混淆文件

## see https://github.com/evant/gradle-retrolambda for java 8
-dontwarn java.lang.invoke.*

Lambda表達式

lambda表達式取代了匿名內部類,取消了模板,允許程序猿用函數式風格編寫代碼,使代碼可讀性更高,儘管剛開始你會看不懂,但是你應該嘗試,畢竟這是新的東西,我已從中獲益。

格式

基本格式是:() -> {}

有下面三種具體表達:

1.(params) -> expression
2.(params) -> statement
3.(params) -> {statement}

使用Java 8 lambda表達式進行事件處理

傳統的點擊事件,應用匿名內部類:

 Button button = new Button(mContext);
 button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(mContext, "button click", Toast.LENGTH_SHORT).show();
            }
        });
    }

如果按照之前Studio配置好了的話會有提示:
這裏寫圖片描述

使用lambda表達式之後是這樣的

button.setOnClickListener(v -> Toast.makeText(mContext, "button click", Toast.LENGTH_SHORT).show());

一行代碼就搞定了,清晰可見,把行爲傳到了函數裏,這裏注意v不可省略,是函數onClick的參數;

傳統實現Runnable接口是這樣的:

new Thread(new Runnable() {
    @Override
    public void run() {
        Log.i("TAG", "haha");
    }
}).start();

使用lambda表達式之後是這樣的:

new Thread(() -> {
    Log.i("TAG", "haha");
}).start();

使用lambda表達式對列表進行迭代

List<String> features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API");
for (String feature : features) {
    System.out.println(feature);
}

// Java 8之後:
List features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API");
features.forEach(n -> System.out.println(n));

// 使用Java 8的方法引用更方便,方法引用由::雙冒號操作符標示,
// 看起來像C++的作用域解析運算符
features.forEach(System.out::println);

輸出結果:
Lambdas
Default Method
Stream API
Date and Time API

使用lambda表達式和函數式接口Predicate

除了在語言層面支持函數式編程風格,Java 8也添加了一個包,叫做 java.util.function。它包含了很多類,用來支持Java的函數式編程。其中一個便是Predicate,使用 java.util.function.Predicate 函數式接口以及lambda表達式,可以向API方法添加邏輯,用更少的代碼支持更多的動態行爲。下面是Java 8 Predicate 的例子,展示了過濾集合數據的多種常用方法。Predicate接口非常適用於做過濾。

public static void main(args[]){
    List languages = Arrays.asList("Java", "Scala", "C++", "Haskell", "Lisp");

    System.out.println("Languages which starts with J :");
    filter(languages, (str)->str.startsWith("J"));

    System.out.println("Languages which ends with a ");
    filter(languages, (str)->str.endsWith("a"));

    System.out.println("Print all languages :");
    filter(languages, (str)->true);

    System.out.println("Print no language : ");
    filter(languages, (str)->false);

    System.out.println("Print language whose length greater than 4:");
    filter(languages, (str)->str.length() > 4);
}

public static void filter(List names, Predicate condition) {
    for(String name: names)  {
        if(condition.test(name)) {
            System.out.println(name + " ");
        }
    }
}

輸出結果:

Languages which starts with J :
Java
Languages which ends with a
Java
Scala
Print all languages :
Java
Scala
C++
Haskell
Lisp
Print no language :
Print language whose length greater than 4:
Scala
Haskell


// 更好的辦法
public static void filter(List names, Predicate condition) {
    names.stream().filter((name) -> (condition.test(name))).forEach((name) -> {
        System.out.println(name + " ");
    });
}

如何在lambda表達式中加入Predicate

上個例子說到,java.util.function.Predicate 允許將兩個或更多的 Predicate 合成一個。它提供類似於邏輯操作符AND和OR的方法,名字叫做and()、or()和xor(),用於將傳入 filter() 方法的條件合併起來。例如,要得到所有以J開始,長度爲四個字母的語言,可以定義兩個獨立的 Predicate 示例分別表示每一個條件,然後用 Predicate.and() 方法將它們合併起來,如下所示:

// 甚至可以用and()、or()和xor()邏輯函數來合併Predicate,
// 例如要找到所有以J開始,長度爲四個字母的名字,你可以合併兩個Predicate並傳入
Predicate<String> startsWithJ = (n) -> n.startsWith("J");
Predicate<String> fourLetterLong = (n) -> n.length() == 4;
names.stream()
    .filter(startsWithJ.and(fourLetterLong))
    .forEach((n) -> System.out.print("nName, which starts with 'J' and four letter long is : " + n));

…還有很多使用方法詳細查看:Java8 lambda表達式10個示例

比較

既然lambda表達式即將正式取代Java代碼中的匿名內部類,那麼有必要對二者做一個比較分析。

第一個關鍵的不同點就是關鍵字 this。匿名類的 this 關鍵字指向匿名類,而lambda表達式的 this 關鍵字指向包圍lambda表達式的類。

第二是編譯方式。Java編譯器將lambda表達式編譯成類的私有方法。使用了Java 7的 invokedynamic 字節碼指令來動態綁定這個方法。

參考:Android Studio 配置

jdk1.8新特性之lambda表達式及在Android Studio中的使用

Java8 lambda表達式10個示例

Java 8簡明教程

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