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简明教程

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