在Java 8中,新增了Lambda表达式功能。那么,Lambda表达式能帮助我们干什么呢?
下面我将用一个真实的例子一步步证明Lambda表达式将会给我们的Coding体验带来非凡的提升。
使用场景如下:
现在,农民伯伯给我们提了一个新的需求,他们希望我们可以开发一个组件,帮助农民伯伯从数量不等的苹果中过滤出绿色的苹果。
为了完成这个需求,需要做如下设计
Version 1:
(1)编写一个苹果的实体类,主要包含三个属性:颜色,重量,品种。
package org.example.lamdba;
import java.util.Arrays;
import java.util.List;
public class Apple {
private String color;
private int weight;
private String variety;
/**
* 空构造函数
*/
public Apple(){
}
/**
* 完全构造函数
* @param color
* @param weight
* @param variety
*/
public Apple(String color,int weight,String variety){
this.color = color;this.weight = weight;this.variety = variety;}
public String getColor() {return color;}
public void setColor(String color) {this.color = color;}
public int getWeight() {return weight;}
public void setWeight(int weight) {this.weight = weight;}
public String getVariety() {return variety}
public void setVariety(String variety) {this.variety = variety;}
public static List sampleList(){
return Arrays.asList(
new Apple("红色",150,"红富士"),new Apple("红色",149,"红富士"),new Apple("绿色",135,"青苹果"),new Apple("绿色",136,"青苹果"),
new Apple("红色",155,"红富士"),new Apple("深红色",145,"红元帅"),new Apple("深红色",142,"红元帅")
);}}
(2): 编写一个Demo类,类名LambdaDemoV1,该Demo类中含有根据颜色过滤的三个方法,并且有可以直接运行的main方法(抱歉,本人不喜欢用Junit的test,哈哈)
package org.example.lamdba;
import java.util.ArrayList;
import java.util.List;
public class LambdaDemoV1 {
public static void main(String[] args) {
List apples = Apple.sampleList();
List blueApples =filterGreenApples(apples);
List redApples =filterRedApples(apples);
List crimsonApples =filterCrimsonApples(apples);
}
//筛选绿苹果
public static List filterGreenApples(List inventory){
List result =new ArrayList<>();
for(Apple apple:inventory){
if("绿色".equals(apple.getColor())){
result.add(apple);}}
return result;
}
//筛选红苹果
public static List filterRedApples(List inventory){
List result =new ArrayList<>();
for(Apple apple:inventory){
if("红色".equals(apple.getColor())){
result.add(apple);}}
return result;
}
//筛选深红苹果
public static List filterCrimsonApples(List inventory){
List result =new ArrayList<>();
for(Apple apple:inventory){
if("深红色".equals(apple.getColor())){
result.add(apple);}}
return result;}}
通过Version 1 版本的设计,我们已经基本完成了农民伯伯的要求,但是,作为开发者,我们需要对上述的通过苹果颜色筛选苹果的方法做一次整合,将颜色作为一个参数,防止添加一个颜色筛选功能就新添加一个方法。
Version 2 :
Coding如下:
//根据苹果的颜色筛选苹果 重新设计filterGreenApples,filterRedApples,filterCrimsonApples方法 =>filterColorApples方法
public static List filterColorApples(List inventory,String color){
List result =new ArrayList<>();
for(Apple apple:inventory){
if(color.equals(apple.getColor())){
result.add(apple);}}
return result;}
经过Version 2 版本的整合,农民伯伯已经可以方便的使用我们提供的工具筛选特定颜色的苹果。但是,现在农民伯伯又提出了一个新的需求,他希望我们可以向他提供一个筛选特定重量苹果的新功能,(农名伯伯将单个苹果的质量超过150g的成为重苹果,小于等于150g的称为轻苹果)
Version 3 Coding: 如下
public class LambdaDemoV3 {
public static void main(String[] args) {
List apples = Apple.sampleList();
List blueApples =filterColorApples(apples,"绿色");
List redApples =filterColorApples(apples,"红色");
List crimsonApples =filterColorApples(apples,"深红色");
List heavyApples =filterApplesByWeight(apples,150);
}
//根据苹果的颜色筛选苹果
public static List filterColorApples(List inventory,String color){
List result =new ArrayList<>();
for(Apple apple:inventory){
if(color.equals(apple.getColor())){
result.add(apple);}}
return result;}
//根据苹果的重量筛选苹果
public static List filterApplesByWeight(List inventory,int weight){
List result =new ArrayList<>();
for(Apple apple:inventory){
if(apple.getWeight() > weight){
result.add(apple);}}
return result;}}
在上面的版本中,新增功能方法filterApplesByWeight,农民伯伯可以通过将weight参数设置成150g方便的筛选出重量150g的苹果集。但是,这时,作为开发者,我们想到了这样一个问题,现在,农民伯伯只提出了通过颜色或者重量属性筛选苹果,要是接下来,农民伯伯希望通过产地,大小等苹果的其它属性进行筛选,怎么办,难道我们要一直增加新的方法吗?当然不是,通过观察学习现有的代码,我们发现其实真正因为功能变化而发生变化的代码只有 if(color.equals(apple.getColor())) => if(apple.getWeight() > weight),其它的都是样板代码(即处理流程)。我们是否可以换一个角度去思考解决这个问题呢?当然有,为此我们提出了一个新的解决方案,即 行为参数化。
Version 4
coding如下:
public interface ApplePredicate {
boolean test (Apple apple);}
public class AppleGreenColorPredicateimplements ApplePredicate{
@Override
public boolean test(Apple apple) {
return "绿色".equals(apple.getColor());}}
public class AppleHeavyWeightPredicateimplements ApplePredicate{
@Override
public boolean test(Apple apple) {
return apple.getWeight() >150;}}
public class LambdaDemoV4 {
public static void main(String[] args) {
List apples = Apple.sampleList();
List heavyApples =filterApples(apples,new AppleGreenColorPredicate());
List greenApples =filterApples(apples,new AppleHeavyWeightPredicate());
}
public static List filterApples(List inventory,ApplePredicate p){
List result =new ArrayList<>();
for(Apple apple:inventory){
if(p.test(apple)){
result.add(apple);}}
return result;}}
在这个版本的Coding中,我们进行了建模,即创建了含有单个函数的接口ApplePredicate。该函数约定返回一个boolean值,而其具体实现需要使用者去创建。之后在改进版的filterApples方法中,将ApplePredicate p 传入参数。这样农民伯伯通过创建ApplePredicate的不同实现就可以使用filterApples提供的颜色,重量,品种等的不同筛选功能。
从开发者的角度考虑,功能组件已经满足了农民伯伯的常用需求,api简单,易用。且开发者以极小的成本代价完成了丰富的功能需求。但是,通过观察代码,我们发现,农民伯伯在使用我们的filterApples时必须先创建实现一个ApplePredicate的子类,再应用filterApples方法。功能的确实现了,但是存在将代码的繁琐由开发者向使用者转嫁的嫌疑。
通过分析,我们决定使用 匿名类的 方式对上述代码做一次优化。
Version 5:
public class LambdaDemoV5 {
public static void main(String[] args) {
List apples = Apple.sampleList();
List heavyApples =filterApples(apples,new ApplePredicate(){
@Override
public boolean test(Apple apple) {
return apple.getWeight() >150;}});
List greenApples =filterApples(apples,new ApplePredicate(){
@Override
public boolean test(Apple apple) {
return "绿色".equals(apple.getColor());}});}
public static List filterApples(List inventory,ApplePredicate p){
List result =new ArrayList<>();
for(Apple apple:inventory){
if(p.test(apple)){
result.add(apple);}}
return result;}}
上述代码中使用了Java 匿名类的方式减少了代码量,但是依旧有些繁琐,接下来,我们可以使用最后一个大招,Lamdba表达式
Version 6:
public class LambdaDemoV6 {
public static void main(String[] args) {
List apples = Apple.sampleList();
List heavyApples =filterApples(apples,(Apple apple) ->apple.getWeight() >150);
List greenApples =filterApples(apples,(Apple apple) ->"绿色".equals(apple.getColor()));
}
public static List filterApples(List inventory,ApplePredicate p){
List result =new ArrayList<>();
for(Apple apple:inventory){
if(p.test(apple)){
result.add(apple);}}
return result;}}
查看上述代码,是不是足够骚浪贱。Java允许我们使用Lambda表达式替代传统的匿名类创建使用方式,当该参数接口是含有单个函数的函数式接口,我们就可以使用Lambda表达式去替代匿名类的使用方式。这就是Lambda的强大之处。极大缩短代码行数,同时大大提高代码的易读性。这时,我们去回看Version 1的代码,当时LambdaDemoV1实现的功能仅有筛选颜色,而且开发了不同的三个方法才完成,转到Version 6的代码,LambdaDemoV6的filterApples方法 可以满足 使用者对苹果的重量,颜色,品种等不同属性的过滤筛选,功能大大增强,同时,使用方面,仅需要农民伯伯编写 List heavyApples =filterApples(apples,(Apple apple) ->apple.getWeight() >150);简短的代码就可以使用了,嗨到爆!
完成这篇博客我花费了将近一天的时间,如果有错误的地方,请及时联系我,谢谢!