为什么要用Lambda表达式?(详细实例解释)

2020-08-21  本文已影响0人  Carter强

        在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);简短的代码就可以使用了,嗨到爆!

完成这篇博客我花费了将近一天的时间,如果有错误的地方,请及时联系我,谢谢!

上一篇下一篇

猜你喜欢

热点阅读