草捏对Lambda表达式的了解停留在用IDEA自动替换匿名类的程度,觉得Lambda表达式只是把代码缩短了而已,不过就是一个语法糖。因此一直不屑一顾,没系统学习。“不过就是代码短一点嘛,没啥大不了”。但经过学习才知道Lambda表达式不单单是把代码换了种表达方式,或许更重要的是背后的思想——行为参数化。编程
所谓的行为参数化,指的是咱们能够经过参数传递的形式去指定代码的行为。是否是很眼熟,学过设计模式的童鞋,基本都是从策略模式开始学起的。策略模式是指面向接口编程,经过使用不一样的实现类,改变具体的行为。行为参数化和策略模式的效果相似,只是多了个参数化,经过传递参数来指定行为。设计模式
下面草捏给你们讲个关于挑苹果的小故事。app
梅梅开始计划天天吃一个苹果,因而吩咐草捏去超市采购。草捏(一个没有生活经验的男人)买苹果的原则:不是烂的就行。ide
// 不是烂的就行 // isRotten = false public static List<Apple> filterApple(List<Apple> apples, boolean isRotten) { List<Apple> result = new ArrayList<>(); for (Apple apple : apples) { if (apple.getRotten().equals(isRotten)) { result.add(apple); } } return result; }
兴致勃勃的买完回到家。
:“草捏,这苹果里咋还有个绿的,我喜欢吃红苹果,要买红的!!!”
:“啊,知道了,知道了, 买红的,下次买红的。”函数
// 此次知道了不只不是烂的,还要买红的 // isRotten = false, color = "red" public static List<Apple> filterApple(List<Apple> apples, boolean isRotten, boolean color) { List<Apple> result = new ArrayList<>(); for (Apple apple : apples) { if (apple.getRotten().equals(isRotten) && apple.getColor().equals(color)) { result.add(apple); } } return result; }
第二次买苹果归来,等待检验。
:“嗯,此次是清一色的红苹果了,但是我喜欢吃小点的苹果,更可爱些,直径应该小于5厘米。”
:“直径...小于...5厘米...”
:“有问题吗?”
:“好的,好的,下次买小于5厘米的。”学习
// 又要加一个参数,直径小于5厘米 // isRotten = false, color = "red", diameter = 5 public static List<Apple> filterApple(List<Apple> apples, boolean isRotten, boolean color, double diameter) { List<Apple> result = new ArrayList<>(); for (Apple apple : apples) { if (apple.getRotten().equals(isRotten) && apple.getColor().equals(color) && (apple.getDiameter() < diameter)) { result.add(apple); } } return result; }
草捏发现,函数的参数已经有4个了,已经不少了,是否是能够考虑改写一下,传递的参数都是挑选苹果的相关标准,而后在函数中根据这些参数来筛选,是否是能够把这些参数抽象成一个结构体,这里抽象成一个Apple类型的变量。设计
public static List<Apple> filterApple(List<Apple> apples, Apple standard) { List<Apple> result = new ArrayList<>(); for (Apple apple : apples) { if (apple.getRotten().equals(standard.isRotten) && apple.getColor().equals(standard.color) && (apple.getDiameter() < standard.diameter)) { result.add(apple); } } return result; }
草捏想这下应该完美了吧,直到第三次回来。
:“草捏,我又想吃大苹果了,下次你买大苹果回来吧。直径大于5厘米的那种。”
这需求变的可真快啊。要大苹果,那就是修改<为>,简单!code
public static List<Apple> filterApple(List<Apple> apples, Apple standard) { List<Apple> result = new ArrayList<>(); for (Apple apple : apples) { if (apple.getRotten().equals(standard.isRotten) && apple.getColor().equals(standard.color) && // 筛选大苹果 (apple.getDiameter() > standard.diameter)) { result.add(apple); } } return result; }
可是看着这两个版本的代码,草捏察觉filterAppple中每次变动的是判断苹果是否符合标准的代码,至于遍历apples和根据判断结果加入到result中这部分是不变化的。因此若是能把判断标准的代码抽象出来,那每次修改的影响就会更小(不用改动filterApple方法)。
定义一个判断苹果标准的接口:接口
// 苹果标准判断 public interface AppleStandardPredicate { // 是否符合标准 boolean isMeetStandard(Apple apple); }
再来个具体实现类,大苹果标准判断:ip
public class BigAppleStandardPredicate implements AppleStandardPredicate { @Override public boolean isMeetStandard(Apple apple) { if (apple.getRotten().equals(false) && apple.getColor().equals("red") && (apple.getDiameter() > 5)) { return true; } return false; } }
把filterApple 的参数改成AppleStandardPredicate,这样filterApple将不会因苹果判断逻辑的变化而变化了。
public static List<Apple> filterApple(List<Apple> apples, AppleStandardPredicate predicate) { List<Apple> result = new ArrayList<>(); for (Apple apple : apples) { if (predicate.isMeetStandard(apple)) { result.add(apple); } } return result; }
让咱们为filterApple传入BigAppleStandardPredicate:
List<Apple> goodApples = filterApple(apples, new BigAppleStandardPredicate());
但这种写法比较繁琐的地方在于须要建立一个实现类,若是用匿名内部类可能会更简洁些。
List<Apple> goodApples = filterApple(apples, new AppleStandardPredicate() { @Override public boolean isMeetStandard(Apple apple) { if (apple.getRotten().equals(false) && apple.getColor().equals("red") && (apple.getDiameter() > 5)) { return true; } return false; } });
嗯,类是少建立了一个,但好像也不是那么简洁,试着用Lambda再稍微简化下。
List<Apple> goodApples = filterApple(apples, apple -> { if (apple.getRotten().equals(false) && apple.getColor().equals("red") && (apple.getDiameter() > 5)) { return true; } return false; });
:“草捏,我不想吃苹果了,我想吃蛇果!标准和以前苹果的同样。”
:“好的。”
这下该怎么改呢?行为仍是原来的行为,可是类型换了。那就用泛型吧。
把AppleStandardPredicate改成带泛型的StandardPredicate:
public interface StandardPredicate<T> { boolean isMeetStandard(T object); }
把filterApple改成带泛型的filter:
public static <T> List<T> filter(List<T> objects, StandardPredicate<T> predicate) { List<T> result = new ArrayList<>(); for (T object : objects) { if (predicate.isMeetStandard(object)) { result.add(object); } } return result; }
最后在调用filter时,只是修改了下变量名,其余都没改,仍然是原来的逻辑。
List<SnakeApple> goodSnakeApples = filter(snakeApples, snakeApple -> { if (snakeApple.getRotten().equals(false) && snakeApple.getColor().equals("red") && (snakeApple.getDiameter() > 5)) { return true; } return false; });
经过类型抽象化,让StandardPredicate和Filter的适用范围扩大化了,不只能够用这段代码挑苹果和蛇果,你还能拿着这段代码去买菜!
:”草捏,去买点卷心菜回来~“
:“好的~”
List<Cabbage> goodCabbages = filter(cabbages, cabbage -> cabbage.getColor().equals("green"));
甚至还能帮老婆挑化妆品!
:”草捏,520快到了,口红用完了~“
:“好的~”
List<Lipstick> goodLipsticks = filter(lipsticks, lipstick -> lipstick.getPrice() > 500);
真是妙啊~ 实乃居家生活之必备~