1.前言
Android中使用Rxjava越来越普遍。而Rxjava结合Lamdba表达式才真正实现代码简洁,所以在此为之后的Rxjava做铺垫,先说一下Lamdba表达式的使用。Lamdba表达式是jdk8之后支持的,主要针对简化匿名内部类代码。
2.环境搭建
为了让jdk8以下的环境使用Lamdba,这里先配置retroLambda插件向下支持。
在Project的build.gradle添加配置
dependencies {
classpath 'com.android.tools.build:gradle:2.2.3'
classpath 'me.tatarka:gradle-retrolambda:3.6.1'
}
repositories {
jcenter()
mavenCentral()
}
然后在module的build.gradle添加配置
apply plugin: 'me.tatarka.retrolambda'
android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
3.使用Lamdba表达式
使用前提
Lamdba表达式主要是用来简化匿名内部类,匿名内部类可以是接口也可以是抽象类,但是有一个前提条件:必须只有一个抽象方法。这样Lambda表达式就可以推断出你简化前的代码
3.1 基本使用: ->
当匿名内部类只有一个抽象方法,此方法可以有返回值,也可以没有返回值,Lambda认为没有必要非要写出这个匿名内部类及方法名,下面直接看例子:
new Thread(new Runnable() {
@Override
public void run() {
Log.d(TAG, "run:_Lambda ");
}
}).start();
那么Lamdba表达式如何简化Runnable这个匿名内部类呢?且看:
new Thread(()-> {Log.d(TAG, "run:_Lambda ");}).start();
可以看到,是如此得简单,规则如下:保留匿名内部类的参数即run方法的 ( ) 和方法体 {Log.d(TAG, “run:_Lambda “);} ,中间使用 -> 连接。即
(参数)->{方法体;}
如果方法体只有一行代码,还可以再简化
new Thread(()-> Log.d(TAG, "run:_Lambda ")).start();
(参数)->一行方法
再举一个常见的例子:常见的点击事件
mTv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
Lambda表达式简化:
mTv.setOnClickListener((View v)-> {finish();});
方法体是一行,再次简化:
mTv.setOnClickListener((View v)-> finish());
3.2 方法引用: ::
Lambda表达式利用 :: 引用类的方法,先看例子:
先构造一个类User:
public class User {
private static final String TAG = "USER";
private String userName;
public User(View view) {
Log.d(TAG, "method: 构造方法");
}
public static void sMethod(View view){
Log.d(TAG, "method: 静态方法");
}
public void mMethod(View view){
Log.d(TAG, "method: 成员方法");
}
public User() {
}
public User(String userName) {
this.userName = userName;
}
public String getUserName() {
return userName;
}
}
注意类的方法的参数类型都是View。
3.2.1 Lambda表达式 :: 引用成员方法
先看之前的使用:
User user = new User();
mTv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
user.mMethod();
}
});
Lambda表达式 :: 简化
User user = new User();
mTv.setOnClickListener(user::mMethod);
之所以可以这样简化,关键就是匿名内部类OnClickListener中的onClick(View v)方法的参数和User的成员方法mMethod(View view)参数一样,这是使用 :: 的条件
3.2.1 Lambda表达式 :: 引用静态方法
之前的使用:
mTv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
User.sMethod(v);
}
});
Lambda表达式 :: 简化
mTv.setOnClickListener(User::sMethod);
同样前提是:匿名内部类的参数和引用的静态方法参数类型一样
3.2.3 Lambda表达式 :: 引用构造方法
之前的使用:
mTv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new User(v);
}
});
Lambda表达式 :: 简化
mTv.setOnClickListener(User::new);
3.2.4 Lambda表达式 :: 类型上的成员方法引用
先看下使用
Function<User, String> getUserName = User::getUserName;
这里的规则是:类名::成员方法,需要注意的一点就是返回的是一个Function类型的,这种类型在什么时候用到呢
Comparator comparator = Comparator.comparing(new Function<User, String>() {
@Override
public String apply(User user) {
return user.getUserName();
}
});
于是这些代码就可以简化为
Comparator comparator = Comparator.comparing(User::getUserName);
Lambda表达式,对静态方法可以直接引用
Comparator comparator = comparing(User::getUserName);
除了以上的这些引用,还有
父类类上的成员方法引用:super::methodName
数组构造方法引用:TypeName[]::new
同样前提是:匿名内部类的参数和引用的构造方法参数类型一样
3.3 Lambda表达式:forEach
Lambda表达式:forEach主要针对的是一些for循环while循环的简化
看下我们之前的写法(增强for):
List<User> users = Arrays.asList(new User[]{new User("Mr.zhang_1"),new User("Mr.zhang_2")});
for (User user : users){
Log.d(TAG, "_Lambda3: user"+user.getUserName());
}
Lambda表达式:forEach简化:
List<User> users = Arrays.asList(new User[]{new User("Mr.zhang_1"),new User("Mr.zhang_2")});
users.forEach(user ->Log.d(TAG, "_Lambda3: user"+user.getUserName()));
这里需要注意一下:forEach要求 minSdkVersion >=24。
3.4 Lambda表达式综合小例子
下面我们实现将一个List 按照用户名就行排序
看下之前的写法:
List<User> users = Arrays.asList(new User[]{new User("Mr.zhang_1"),new User("Mr.zhang_2")});
Collections.sort(users, new Comparator<User>() {
@Override
public int compare(User u1, User u2) {
return u1.getUserName().compareTo(u2.getUserName());
}
});
先看下Lambda表达式简化的结果:
users.sort(comparing(User::getUserName));
这样一下可能不太好看懂,下面解释下简化的过程:
① 去掉匿名内部类Comparator和方法名compare
Collections.sort(users,(User u1, User u2) ->u1.getUserName().compareTo(u2.getUserName()));
②使用Comparator.comparing()进行比较
Collections.sort(users,Comparator.comparing((User u)->u.getUserName()));
③这样静态方法可以直接引入
Collections.sort(users,comparing((User u)->u.getUserName()));
④Lambda类型推断
Collections.sort(users,comparing(u->u.getUserName()));
⑤ :: 双冒号方法引用
Collections.sort(users,comparing(User::getUserName));
⑥ 使用List的sort方法进一步简化
users.sort(comparing(User::getUserName));
这样就大功告成