简介
Lambda
是一个匿名函数,我们可以把Lambda
表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。可以写出更简洁、更灵活的代码。作为一种更紧凑的代码风格,使Java
的语言表达能力得到了提升。
示例
我们先来回顾一下匿名内部类的写法:
// 原始匿名内部类
@Test
public void test1() {
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("hello world");
}
};
runnable.run();
}
上面所示的是原始的匿名内部类的写法,主体内容需要写好多行代码。
下面我们来看一下使用lambda
表达式的写法:
// 从匿名内部类到Lambda 表达式
@Test
public void test2() {
Runnable runnable = () -> System.out.println("hello world");
runnable.run();
}
原始匿名内部类的方式需要写好多行代码,lambda
表达式一行就搞定了。
感受到了lambda
的魅力了吧,别急,精彩的还在后面呢!
假设我们现在有一个需求,就是根据条件来筛选用户,比如筛选性别为男的用户。
定义一个用户类:
public class User {
private String name; // 名称
private String gender; // 性别
private int age; // 年龄
public User(String name, String gender, int age) {
this.name = name;
this.gender = gender;
this.age = age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", gender='" + gender + '\'' +
", age=" + age +
'}';
}
}
定义一个根据性别筛选性别为男的方法:
/**
* 筛选出性别为男的用户
*
* @param users
* @return
*/
public List<User> filterUserByGender(List<User> users) {
List<User> result = new ArrayList<>();
for (User user : users) {
if ("男".equals(user.getGender())) {
result.add(user);
}
}
return result;
}
定一个成员变量,用户list:
List<User> userList = new ArrayList<>(Arrays.asList(
new User("小明", "男", 20),
new User("小红", "女", 30),
new User("小张", "男", 40)
));
测试:
// 需求:筛选用户
@Test
public void test3() {
List<User> users = filterUserByGender(userList);
for (User user : users) {
System.out.println(user);
}
输出结果:
User{name='小明', gender='男', age=20}
User{name='小张', gender='男', age=40}
OK,筛选性别为男的用户的功能实现了,那假设现在又要筛选年龄大于30岁的用户呢?
有同学会想到,将筛选性别为男的方法copy一份,判断条件改一下不就行了。我们来实现一下:
/**
* 筛选年龄大于30的用户
*
* @param users
* @return
*/
public List<User> filterUserByAge(List<User> users) {
List<User> result = new ArrayList<>();
for (User user : users) {
if (user.getAge() > 30) {
result.add(user);
}
}
return result;
}
测试:
// 需求:筛选用户
@Test
public void test3() {
List<User> users = filterUserByGender(userList);
for (User user : users) {
System.out.println(user);
}
System.out.println("-------------------------------------");
List<User> users1 = filterUserByAge(userList);
for (User user : users1) {
System.out.println(user);
}
}
输出结果:
User{name='小明', gender='男', age=20}
User{name='小张', gender='男', age=40}
-------------------------------------
User{name='小张', gender='男', age=40}
OK,筛选年龄大于30岁的功能也实现,但是仔细想想,上面的实现方式虽然能实现功能,但代码太冗余了,复用率太低了。
下面我们来优化一下。
优化方式一:使用策略模式:
定义一个范型Filter
接口:
public interface Filter<T> {
boolean test(T t);
}
定义相关的过滤器:
筛选年龄大于三十的用户:
public class UserFilterByAge implements Filter<User> {
@Override
public boolean test(User user) {
if(user.getAge() > 30){
return true;
}
return false;
}
}
筛选性别为男的用户:
public class UserFilterByGener implements Filter<User> {
@Override
public boolean test(User user) {
if("男".equals(user.getGender())){
return true;
}
return false;
}
}
定义一个筛选方法:
public List<User> filterUser(List<User> users, Filter<User> filter) {
List<User> result = new ArrayList<>();
for (User user : users) {
if (filter.test(user)) {
result.add(user);
}
}
return result;
}
测试:
// 优化方式一:使用策略设计模式
@Test
public void test4() {
List<User> users = filterUser(userList, new UserFilterByGener());
for (User user : users) {
System.out.println(user);
}
System.out.println("-------------------------------------");
List<User> users1 = filterUser(userList, new UserFilterByAge());
for (User user : users1) {
System.out.println(user);
}
}
输出结果:
User{name='小明', gender='男', age=20}
User{name='小张', gender='男', age=40}
-------------------------------------
User{name='小张', gender='男', age=40}
可以看到,我们只需要传入不同的筛选策略即可,即使后面需要增加其它筛选条件,也只需新增实现类即可。
有的同学看到这里可能想说,每加一个筛选条件,就需要增加相应的策略类,策略类里面起到的作用的其实就一个条件判断,显得有些多余。
我们带着这个问题,接着优化。
优化方式二:匿名内部类:
// 优化方式二:匿名内部类
@Test
public void test5() {
List<User> users = filterUser(userList, new Filter<User>() {
@Override
public boolean test(User user) {
return user.getAge() > 30;
}
});
for (User user : users) {
System.out.println(user);
}
}
我们结合匿名内部类,重写了test方法,实现自己想要的筛选条件,这样就不用新增策略类了。
既然可以使用匿名内部类,在文章开头,我们有讲到匿名内部类结合lambda
的使用方式,我们来改成lambda的方式。
优化方式三:lambda表达式:
// 优化方式三:lambda表达式
@Test
public void test6() {
List<User> users = filterUser(userList, User -> User.getAge() > 30);
// List<User> users = filterUser(userList, (e) -> e.getAge() > 30);
users.forEach(System.out::println);
}
有的同学可能感觉还不够过瘾,下面接下来看优化方式四:Stream API:
// 优化方式四:Stream API
@Test
public void test7() {
userList.stream().filter(User -> User.getAge() > 30).forEach(System.out::println);
System.out.println("-------------------------------------");
List<User> users = userList.stream().filter(User -> "女".equals(User.getGender())).collect(Collectors.toList());
users.forEach(System.out::println);
}
看到这段代码,是不是感觉很神奇,前面写的什么策略类呀,筛选方法啥的都可以不用要了,使用Stream API
,一行代码搞定。
在这里我们先带入Stream API
,简单使用了一下,此处不做过多讲解,在后面会再详细介绍。
OK,上面我们集合实际案例介绍了lambda的基本使用,下面我们来介绍一下lambda的语法。
语法介绍
Lambda
表达式在Java 语言中引入了一个新的语法元素和操作符。这个操作符为->
,该操作符被称为Lambda 操作符或剪头操作符。它将Lambda
分为两个部分:
左侧:指定了Lambda
表达式需要的所有参数
右侧:指定了Lambda
体,即Lambda
表达式要执行的功能。
- 语法格式一:无参数,无返回值:
() -> System.out.println("Hello Lambda");
@Test
public void test1(){
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("Hello World");
}
};
runnable.run();
System.out.println("--------------------------------");
Runnable runnable1 = () -> System.out.println("Hello Lambda");
runnable1.run();
}
- 语法格式二:有一个参数,无返回值:
(e) -> System.out.println(e);
@Test
public void test2(){
Consumer<String> consumer = (e) -> System.out.println(e);
consumer.accept("语法格式二:有一个参数,无返回值");
}
- 语法格式三:有一个参数时,小括号可以省略不写:
e -> System.out.println(e);
@Test
public void test3(){
Consumer<String> consumer = e -> System.out.println(e);
consumer.accept("语法格式二:有一个参数时,小括号可以省略不写");
}
- 语法格式四:多个参数,有返回值,lambda体中有多条语句
@Test
public void test4(){
Comparator<Integer> comparable = (x, y) -> {
System.out.println("多个参数,有返回值,lambda体中有多条语句");
return Integer.compare(x,y);
};
}
- 语法格式五:多个参数,有返回值,lambda体中有一条语句,打括号和return可以不写
@Test
public void test5(){
Comparator<Integer> comparable = (x, y) -> Integer.compare(x,y);
}