Java 8的一个大亮点是引入Lambda表达式,使用它设计的代码会更加简洁。而且可以更加适应不断变化的需求;
下面我们循序渐进从案例入手
一:传统的应对列表筛选的解决方案
下面给出一个例子:
public static List<Apple> filterApple(List<Apple> appleList){ List<Apple> apples = new ArrayList<>(); for (Apple apple : appleList) { if (Objects.equals(apple.getColor(), "green")){ apples.add(apple); } } return apples; }
此代码的意思是从一堆苹果中筛选出绿色的苹果。
假如哪一天,这位农民伯伯不想筛选绿色的苹果,想筛选红色的苹果,那么我们应该怎么做呢?
最简单的方法就是将上述的代码复制过来,然后改个条件,
但是后续的需求变动是不确定,那么我们应该怎么面对这种变化的需求?
此时进阶的做法就是将条件作为参数传入filterApple方法中,例子如下
public static List<Apple> filterAppleByCondition(List<Apple> appleList,String color){ List<Apple> apples = new ArrayList<>(); for (Apple apple : appleList) { if (Objects.equals(apple.getColor(), color)){ apples.add(apple); } } return apples; }
上述代码很完美的解决了筛选苹果颜色的各种需求,但是现在要对苹果的重量进行筛选呢?是不是懵逼了,那我们改写一下程序
public static List<Apple> filterApple(List<Apple> appleList,double weight){ List<Apple> apples = new ArrayList<>(); for (Apple apple : appleList) { if(Double.compare(apple.getWeight(),weight)>0){ apples.add(apple); } } return apples; }
这样也完美的解决了筛选苹果的需求,但是,接下来又有需求要一套方法解决筛选苹果的颜色和重量,改写程序如下
/** * flag 为true则筛选颜色,flag为false筛选重量 * @param appleList * @param color * @param weight * @param flag * @return */ public static List<Apple> filterApple(List<Apple> appleList,String color,double weight,boolean flag){ List<Apple> apples = new ArrayList<>(); for (Apple apple : appleList) { if((!flag&&Double.compare(apple.getWeight(),weight)>0)||(flag&&Objects.equals(apple.getColor(), color))){ apples.add(apple); } } return apples; }
上述代码有以下几个缺点:
1,flag含义不确定
2,此方法无法应对更加富有变化的需求
二,行为参数化
对筛选苹果这一需求进行建模。
现在我们的需求是对苹果的属性进行筛选,返回值是一个boolean类型,那么我们建立一个接口
public interface ApplePredicate { public boolean test(Apple apple); }
此接口的实现即可作为筛选苹果的入参,作为一个行为参数传递给筛选苹果的方法
public class AppleColorPredicate implements ApplePredicate { @Override public boolean test(Apple apple) { return "green".equals(apple.getColor()); } } public class AppleWeightPredicate implements ApplePredicate { @Override public boolean test(Apple apple) { return Double.compare(apple.getWeight(),30)>0; } }
经过改造后的筛选苹果方法如下:
public static List<Apple> filterApple(List<Apple> appleList,ApplePredicate predicate){ List<Apple> apples = new ArrayList<>(); for (Apple apple : appleList) { if(predicate.test(apple)){ apples.add(apple); } } return apples; }
这种做法就是借鉴了策略模式。建立一个统一的上层接口,利用不用的实现作为策略;
我们现在迈出了行为参数化的第一步,但是很遗憾的是,我们的行为必须通过对象的形式传递给方法
那么,我们有没有办法直接将代码传递给方法呢?有的,lambda表达式
List<Apple> red = FilterAppleList.filterApple(appleList, apple -> { return Objects.equals(apple.getColor(), "red"); });