行为参数话的理解:
行为参数化有些类似策略模式,但是更精简。表面来看就是定义一个函数式接口(只定义一个抽象方法的接口),实现这个接口然后把实现类的实例当做参数加入到方法中。行为参数化可以很好的应对不断变更的需求,使代码更优雅。
下面看看示例(来自《Java8实战》)
模拟场景:我们有个客户是水果大王,他想要一个系统来帮助他快速的把收来的苹果进行分类然后分销的不同的地区。第一次跟他谈需求,他说他想要把重量大于5kg的苹果发往西北,把重量小于5kg的苹果发往华东。我们根据他的需求开始开发,
做到中途,水果大王突然联系我们说需要改需求,他还想根据颜色来把苹果分来然后发往不同的区域。我们眉头一皱,还好我们可以用行为参数化的方法来改需求。否则又是浩大的工作量啊!
步骤一:定义一个苹果类
package org.burning.sport.javase.lambda; public class Apple { private int weight; private String color; public Apple(int weight, String color) { this.weight = weight; this.color = color; } setters();getters();toString(); }
步骤二:定义一个函数式接口,这个接口里的抽象方法就是用来规定怎么区分苹果的,返回一个boolean值
package org.burning.sport.javase.lambda; /** * 函数式接口 */ public interface ApplePredicate { boolean test(Apple apple); }
步骤三:定义两个实现类,分别是区分颜色的和区分重量的
package org.burning.sport.javase.lambda; public class AppleColorPredicate implements ApplePredicate { /** 筛选出红色的苹果 */ @Override public boolean test(Apple apple) { return "red".equals(apple.getColor()); } }
package org.burning.sport.javase.lambda; public class AppleWeightPredicate implements ApplePredicate{ /** 筛选出重量大于5kg的苹果 */ @Override public boolean test(Apple apple) { return apple.getWeight() > 5; } }
步骤四:使用行为参数
package org.burning.sport.javase.lambda; import java.util.ArrayList; import java.util.List; /** * 行为参数化示例 */ public class LambdaTest1 { public static List<Apple> filterApples(List<Apple> apples, ApplePredicate predicate) { List<Apple> result =new ArrayList<>(); for(Apple apple : apples) { if(predicate.test(apple)) { result.add(apple); } } return result; } public static void main(String[] args) { List<Apple> appleList = new ArrayList<>(); appleList.add(new Apple(10, "green")); appleList.add(new Apple(5, "red")); appleList.add(new Apple(5, "green")); appleList.add(new Apple(10, "red")); //找出颜色是红色的苹果 List<Apple> resultColor = filterApples(appleList, new AppleColorPredicate()); System.out.println(resultColor.toString()); //找出重量大于5的苹果 List<Apple> resultWeight = filterApples(appleList, new AppleWeightPredicate()); System.out.println(resultWeight.toString()); } }
看了上面的例子,我们发现还不是很灵活,如果水果大王又开始卖橙子卖香蕉了呢?所以我们再做一下改造,用到了泛型,将行为参数泛型化。
步骤一:定义一个泛型化的函数接口
package org.burning.sport.javase.lambda; public interface Predicate<T> { boolean test(T t); }
步骤二:定义一个橙子实体类
package org.burning.sport.javase.lambda; public class Orange { private int weight; private String color; public Orange(int weight, String color) { this.weight = weight; this.color = color; } setters();getters();toString(); }
步骤三:定义两个实现类,分别是区分橙子的颜色和重量
package org.burning.sport.javase.lambda; public class ColorPredicate implements Predicate<Orange> { @Override public boolean test(Orange orange) { //筛选出橙色的橙子 return "orange".equals(orange.getColor()); } }
package org.burning.sport.javase.lambda; public class WeightPredicate implements Predicate<Orange> { @Override public boolean test(Orange orange) { //筛选出大于5kg的橙子 return orange.getWeight() > 5; } }
步骤四:使用新定义的泛型化行为参数
package org.burning.sport.javase.lambda; import com.google.common.collect.Lists; import java.util.ArrayList; import java.util.List; public class LambadTest2 { public static <T> List<T> filter(List<T> fruits, Predicate<T> predicate) { List<T> results= new ArrayList<>(); for(T t : fruits) { if(predicate.test(t)) { results.add(t); } } return results; } public static void main(String[] args) { ArrayList<Orange> oranges = Lists.newArrayList( new Orange(10, "green"), new Orange(4, "green"), new Orange(4, "orange"), new Orange(10, "green")); List<Orange> resultColorList = filter(oranges, new ColorPredicate()); System.out.println(resultColorList.toString()); System.out.println("================="); List<Orange> resultWeightList = filter(oranges, new WeightPredicate()); System.out.println(resultWeightList.toString()); } }
上面的例子有很好的扩展性,还可以。但是还是得多写两个“套路”的实现类,有没有更简洁一点的“套路”呢?有,用Lambda表达式
package org.burning.sport.javase.lambda; import com.google.common.collect.Lists; import java.util.ArrayList; import java.util.List; public class LambdaTest3 { public static <T> List<T> filter(List<T> fruits, Predicate<T> predicate) { List<T> results= new ArrayList<>(); for(T t : fruits) { if(predicate.test(t)) { results.add(t); } } return results; } public static void main(String[] args) { ArrayList<Orange> oranges = Lists.newArrayList( new Orange(10, "green"), new Orange(4, "green"), new Orange(4, "orange"), new Orange(10, "green")); ArrayList<Apple> apples = Lists.newArrayList( new Apple(10, "red"), new Apple(10, "green"), new Apple(3, "red"), new Apple(3, "green")); // Lambda表达式 List<Orange> orangeWeightList = filter(oranges, o -> o.getWeight() > 5); List<Apple> appleWeightList = filter(apples, a -> a.getWeight() > 5); System.out.println(orangeWeightList); System.out.println("==============="); System.out.println(appleWeightList); } }
最后再补充几个概念吧:
1、任何函数式接口都不允许抛出受检查异常(check exception)
2、Lambda仅可用于上下文是函数式接口的情况
好啦,就这样吧,现学现卖结束啦。
https://gitee.com/play-happy/base-project
参考:
【1】《Java8实战》