目录结构:
1:怎么在studio中使用lambda表达式;
2:lambda表达式的使用;
1:怎么在studio中使用lambda表达式
怎么在Android studio项目里面使用java 8的新特性功能lambda表达式呢?
google developer 官方文档里面提供了3种方法:
方法
前提使用JAVA 8
1:使用jack工具链;
jack方式
配置 Gradle
要为您的项目启用 Java 8 语言功能和 Jack,请在模块级别的 build.gradle 文件中输入以下内容:
android {
...
defaultConfig {
...
jackOptions {
enabled true
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
Instant Run 目前不能用于 Jack,在使用新的工具链时将被停用,所以不建议使用这种方式.
2:使用 Retrolambda插件
配置Gradel
要为您的项目启用 Java 8 语言功能和 retrolambda,请在模块级别的 build.gradle 文件中输入以下内容:
android {
...
defaultConfig {
...
}
// Keep the following configuration in order to target Java 8.
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
apply plugin: 'me.tatarka.retrolambda'
不明白的细节可以看官方文档
buildscript {
...
dependencies {
classpath 'me.tatarka:gradle-retrolambda:<version_number>'
}
}
gradle-retrolambda版本选择
gradle-retrolambda官方文档
3:
前面两种是使用插件完成,第三种,看google文档中写到,Android studio 3.0 preview 1之后,可以不适用工具链插件. 明确指出禁用jack工具链.
前提
To start using supported Java 8 language features, update the Android plugin to 3.0.0-alpha1
(or higher) and add the following to your module’sbuild.gradle
file:
这里的这个plugin 3.0.0-alpha1 不知道怎么搞.等回头试过了更新此部分.
// Keep the following configuration in order to target Java 8.
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
目前推荐使用gradle-retrolambda插件的这种方式.
2:lambda表达式的使用
lambda 表达式有三种形式,分别是:
a:函数式接口
b:方法引用
c:构造器引用
Lambda 表达式由参数列表、箭头和 Lambda 主体(语句块)组成。
( 参数列表... ) -> { 语句块... }
lambda表达式 | 含义 |
---|---|
(String s) -> s.length() | 表达式具有一个 String 类型的参数并返回一个 int。 Lambda 没有 return 语句,因为已经隐含的 return,可以显示调用 return。 |
(T t) -> R | 传入参数T,返回一个R类型 |
(T t) -> void | 传入参数T,不返回任何内容 |
(T1 t,T2 t2,...) -> R | 传入多个参数,返回一个R类型 |
(T1 t,T2 t2,...) -> void | 传入多个参数,不返回任何内容 |
使用lambda表达式的前提是:一个只定义了一个抽象方法的接口,或抽象类.
函数式接口
方法引用
以 Java 的 Predicate 接口作为示例,此接口用来实现判断功能,我们来对字符串进行全面的判空操作:
TextUtils 的 isEmpty() 方法实现了上述功能,所以我们可以写作:
方法引用形式就是当逻辑实现只有一句且调用了已存在的方法进行处理( this 和 super 的方法也可包括在内)时,对函数式接口形式的 lambda 表达式进行进一步的简化。传入引用方法的参数就是原接口方法的参数。
接下来总结一下方法引用形式的三种格式:
object :: instanceMethod
直接调用任意对象的实例方法,如 obj::equals 代表调用 obj 的 equals 方法与接口方法参数比较是否相等,效果等同 obj.equals(t);。
ClassName :: staticMethod
当前类的方法可用this::method进行调用,父类方法同理。
直接调用某类的静态方法,并将接口方法参数传入,如上述 TextUtils::isEmpty,效果等同 TextUtils.isEmpty(s);
ClassName :: instanceMethod
较为特殊,将接口方法参数列表的第一个参数作为方法调用者,其余参数作为方法参数。由于此类接口较少,故选择 Java 提供的 BiFunction 接口作为示例,该接口方法接收一个 T1 类对象和一个 T2 类对象,通过处理后返回 R 类对象
值得注意的是方法引用图2中的这种方式,固定第一个参数作为方法调用者,其他参数作为方法参数
构造器引用
对于一个现有构造函数,可以利用它的名称和关键字 new 来创建它的一个引用:ClassName::new。它的功能与指向静态方法的引用类似。
例如,假设有一个构造函数没有参数。 它适合 Supplier 的签名() -> Apple。可以这样做:
Supplier<Apple> c1 = Apple::new; //构造函数引用指向默认的 Apple() 构造函数
Apple a1 = c1.get(); //产生一个新的对象
//等价于:
Supplier<Apple> c1 = () -> new Apple(); //利用默认构造函数创建 Apple 的 Lambda 表达式
Apple a1 = c1.get();
Supplier接口
@FunctionalInterface
public interface Supplier<T> {
/**
* Gets a result.
*
* @return a result
*/
T get();
}
如果你的构造函数的签名是Apple(Integer weight),那么它就适合 Function 接口的签名,于是可以这样写:
Function<Integer, Apple> c2 = Apple::new; //构造函数引用指向 Apple(Integer weight) 构造函数
Apple a2 = c2.apple(100);
//等价于:
Function<Integer, Apple> c2 = (Integer weight) -> new Apple(weight);
Apple a2 = c2.apple(100);
类型检查
Lambda 的类型是从使用 Lambda 的上下文推断出来的。上下文(比如接受它传递的方法的参数,或接受它的值的局部变量)中 Lambda 表达式需要的类型称为目标类型。下图表示了代码的类型检查过程:
首先,找出 filter 方法的声明;
第二,找出目标类型 Predicate<Apple>。
第三,Predicate<Apple>是一个函数式接口,定义了一个叫作 test 的抽象方法。
第四,test 方法描述了一个函数描述符,它可以接受一个 Apple,并返回一个 boolean。
最后,filter 的任何实际参数都必须匹配这个要求。
搬东搬西凑成了这篇笔记,时不时自己好回忆下.
参考链接
2:郭神公众号