从Java8开始,引入了一个新功能,那就是Lambda。
为什么加入了这个功能呢?
因为现在脚本语言或者说函数式编程越来越流行,函数式编程的优势在于代码更简洁了,而且更易于理解,更重要的式代码更加灵活、功能也变的更强大,还有一个优点就是函数式编程,对程序员写代码更加高效了,因为以前你实现一个功能可能要写十几行甚至几十行代码,现在使用了Java Lambda的函数式编程方式,可能几行代码,甚至一行代码就能搞定,即便应对复杂的编写逻辑,也能灵活应对,简化编写过程。
简单来说,Java的Lambda表达式一是简化代码,让编写更流程;二是将函数变为了一等公民,能像变量一样传递;三是对并行的支持。
说完了有点,我们用代码来体验一下Lambda的魅力。
比如我有一筐苹果,我要按照颜色分类,分为红苹果和绿苹果。我们先定义一个苹果类,如下:
package com.itzhimei.study.lambda.unit2;
import lombok.Data;
/**
* @Auther: www.itzhimei.com
* @Description:
*/
@Data
public class Apple {
private String color;
private int weight;
public Apple(String color, int weight) {
this.color = color;
this.weight = weight;
}
}
我现在要根据颜色把苹果分成红苹果和绿苹果,你可能会想到,用if判断一下苹果颜色就可以了,根据不同颜色,放到不同分组重,代码如下:
for(Apple a: apples) {
if(a.getColor().equals("红苹果")) {
System.out.println("发现一个红苹果");
} else {
System.out.println("发现一个绿苹果");
}
}
这时我们Java8之前的常用写法。但是如果现在需求变复杂了,我不仅要区分颜色,还要区分重量,甚至是颜色和重量一起分,红色苹果大于150g的找出来,该怎么做?
还用 if(条件A && 条件B && 条件C &&…) ,或者if-else嵌套吗?
是可以的,但是代码不够优雅,也不好维护,因为我们实际的业务可能比这复杂很多,这里的if就变成了一个庞大的逻辑判断代码块,稍有不慎就改出bug了。
我们再来看看建模改进版。
有的同学会说,我们可以根据不同的逻辑,创建一个处理类,根据不同需求,使用不同除了处理类(这就是策略模式),这样确实可以,而且代码的扩展性也变好了,如果新增了其他逻辑需求,我新增一个对应的处理类就可以了。
代码如下:
1、新建一个抽象处理类
package com.itzhimei.study.lambda.unit2;
/**
* @Auther: www.itzhimei.com
* @Description:
*/
public interface AppleFormatter {
String accept(Apple apple);
}
2、新建判断苹果重量的实现类
package com.itzhimei.study.lambda.unit2;
/**
* @Auther: www.itzhimei.com
* @Description:
*/
public class AppleFormatterA implements AppleFormatter {
@Override
public String accept(Apple apple) {
return apple.getWeight()>150?"重苹果":"轻苹果";
}
}
3、新建用于打印苹果重量的处理类
package com.itzhimei.study.lambda.unit2;
/**
* @Auther: www.itzhimei.com
* @Description:
*/
public class AppleFormatterB implements AppleFormatter {
@Override
public String accept(Apple apple) {
return apple.getColor() + "的重量是:" + apple.getWeight() + "g";
}
}
4、测试
package com.itzhimei.study.lambda.unit2;
import java.util.ArrayList;
import java.util.List;
/**
* @Auther: www.itzhimei.com
* @Description: 行为参数化 建模:每种逻辑实现接口里的方法,策略模式,优点易于理解,符合我们开发逻辑; 缺点:类多
*/
public class Lambda2_2_1 {
public static void main(String[] args) {
List<Apple> apples = new ArrayList<>();
Apple a1 = new Apple("红苹果",155);
Apple a2 = new Apple("绿苹果",136);
Apple a3 = new Apple("红苹果",169);
apples.add(a1);
apples.add(a2);
apples.add(a3);
printApple(apples, new AppleFormatterA());
printApple(apples, new AppleFormatterB());
}
public static void printApple(List<Apple> apples, AppleFormatter af) {
for(Apple a : apples) {
System.out.println(af.accept(a));
}
}
}
我们在测试代码中定义了一个使用策略类的方法printApple,根据传入的策略类的不同,就能产生不同的功能效果。
输出:
重苹果
轻苹果
重苹果
红苹果的重量是:155g
绿苹果的重量是:136g
红苹果的重量是:169g
这种策略模式的改进,已经一定程度上能应对需求的变化了,但是,缺点是类会非常多。
为了简化类的数量,java8之前,我们可以使用匿名类进行改造,也能达到上面的效果。
package com.itzhimei.study.lambda.unit2;
import java.util.ArrayList;
import java.util.List;
/**
* @Auther: www.itzhimei.com
* @Description: 行为参数化 使用内部类简化代码,减少了类的创建,但是代码不易读
*/
public class Lambda2_2_2 {
public static void main(String[] args) {
List<Apple> apples = new ArrayList<>();
Apple a1 = new Apple("红苹果",155);
Apple a2 = new Apple("绿苹果",136);
Apple a3 = new Apple("红苹果",169);
apples.add(a1);
apples.add(a2);
apples.add(a3);
printApple(apples, new AppleFormatter(){
@Override
public String accept(Apple apple) {
return apple.getWeight()>150?"重苹果":"轻苹果";
}
});
printApple(apples, new AppleFormatter(){
@Override
public String accept(Apple apple) {
return apple.getColor() + "的重量是:" + apple.getWeight() + "g";
}
});
}
public static void printApple(List<Apple> apples, AppleFormatter af) {
for(Apple a : apples) {
System.out.println(af.accept(a));
}
}
}
但是匿名类的缺点就是不易读,难理解,而且如果大量使用匿名类,代码就非常不美观了。
那么接下来就是我们今天的主角了,看看使用lambda后代码的效果。
package com.itzhimei.study.lambda.unit2;
import java.util.ArrayList;
import java.util.List;
/**
* @Auther: www.itzhimei.com
* @Description: 行为参数化 使用lambda表达式简化代码
*/
public class Lambda2_2_3 {
public static void main(String[] args) {
List<Apple> apples = new ArrayList<>();
Apple a1 = new Apple("红",155);
Apple a2 = new Apple("绿",136);
Apple a3 = new Apple("红",169);
apples.add(a1);
apples.add(a2);
apples.add(a3);
printApple(apples, (Apple apple) -> apple.getColor().equals("红")?"红苹果":"绿苹果");
System.out.println("---------------------------");
printApple(apples, (Apple apple) -> apple.getWeight()>150?"重苹果":"轻苹果");
}
public static void printApple(List<Apple> apples, AppleFormatter af) {
for(Apple a : apples) {
System.out.println(af.accept(a));
}
}
}
重点看这里:
printApple(apples, (Apple apple) -> apple.getColor().equals("红")?"红苹果":"绿苹果");
这就是lambda的最简单的用法之一。我们将原来写在策略类中的判断或者写在匿名类中的判断逻辑,变成了一个表达式,却实现了同样的效果,也仅仅只是一行代码。
上面的代码看不懂不要紧,重点是体会一下lambda的效果,后面我会一点一点学会,学懂,直到熟练应用。
上面这种写法,就叫做:行为参数化。
也就是你将一个类似方法的东西,作为参数,传入另了一个方法,在这个传入的方法中,再应用这个被当作参数的方法,这就是行为参数化。
仅仅是这一个特性,就能让我们的代码变的无限强大和灵活,这个我们通过后面的学习再来体会。
本文及后续课程参考内容:《Java 8实战》、《精通lambda表达式:Java多核编程》