前面 Java 8之方法引用和Lambda表达式这篇文章讲了 方法引用和 Lambda表达式的大体原理和使用方法,可是光有理论是不够的,如今这篇文章会讲到它们的实际应用,从最开始的需求一步步的优化代码,直到最后使用Lambda表达式。
咱们如今有个Apple类,它有weight和color属性分别表明它的重量和属性,咱们建立多个苹果放入List中,这样就有了不少不一样的苹果。segmentfault
public class Apple { private String color; private Integer weight; public Apple(String color, Integer weight) { this.color = color; this.weight = weight; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } public Integer getWeight() { return weight; } public void setWeight(Integer weight) { this.weight = weight; } @Override public String toString() { return "Apple{" + "color='" + color + '\'' + ", weight=" + weight + '}'; } } public static void main(String[] args) { List<Apple> apples = new ArrayList<Apple>(); Apple apple1 = new Apple("red", 100); Apple apple2 = new Apple("green", 200); Apple apple3 = new Apple("red", 300); Apple apple4 = new Apple("red", 150); apples.add(apple1); apples.add(apple2); apples.add(apple3); apples.add(apple4); }
假设咱们如今有个Apple类,它有weight和color属性,如今有个需求,把红色的苹果挑出来,咱们就写出了下列的代码。下面这段代码再常见不过了,把未分类的集合传进来,新建一个集合把筛选出来的元素放进去再返回,可是若是需求说要把绿色的都筛选出来呢?难道复制一个吗?那也太傻了,因此咱们须要对代码进行改进。设计模式
public static List<Apple> filterGreenApples(List<Apple> apples) { List<Apple> result = new ArrayList<Apple>(); for (Apple apple : apples) { if ("green".equals(apple.getColor())) { result.add(apple); } } return result; }
通过咱们的改进,把要筛选的颜色也看成参数传进来方法,这样想选什么样颜色就选什么颜色,可是需求永远都是会变得,若是说除了颜色还要再加上重量做为筛选呢?因此咱们又对代码进行了改进。app
public static List<Apple> filterApplesByColor(List<Apple> apples, String color) { List<Apple> result = new ArrayList<Apple>(); for (Apple apple : apples) { if (apple.getColor().equals(color)) { result.add(apple); } } return result; }
既然要加多重量做为筛选条件,那干脆把重量也看成参数传进去,这个时候咱们发现这段代码开始变得很恶心了,在项目很赶的时候不少人会写出相似这种代码,需求是实现了,可是几乎没有什么阅读性可言,并且最多过一个星期,连你本身均可能看不懂本身写的什么东西,并且若是代码没有BUG也就算了,有了隐藏BUG在中途被发现再改的话是越改越乱,因此确定不能用这样的代码,咱们得再改进代码。ide
public static List<Apple> filterApples(List<Apple> apples, String color, int weight, boolean flag) { List<Apple> result = new ArrayList<Apple>(); for (Apple apple : apples) { if ((flag && apple.getColor().equals(color)) || (!flag && apple.getWeight() > weight)) { result.add(apple); } } return result; }
如今封装方法的方式已经没办法很好的解决问题了,因此咱们决定使用设计模式中的策略模式解决这个问题,咱们新建一个接口,里面定义一个方法接受Apple
参数,而后咱们只要实现这个接口重写这个方法,就能够在这个方法里面自定义咱们的筛选代码了,咱们能够直接用匿名类省去建立类的步骤,这也是最经常使用的方法,好比新建线程传入Runnable接口就是这样的作法优化
public interface ApplePredicate { boolean test(Apple apple); } public class AppleHeavyWeightPredicate implements ApplePredicate { public boolean test(Apple apple) { return apple.getWeight() > 150; } } public static List<Apple> filterApples(List<Apple> apples, ApplePredicate p) { List<Apple> result = new ArrayList<Apple>(); for (Apple apple : apples) { if (p.test(apple)) { result.add(apple); } } return result; } //使用匿名类 List<Apple> redApples = filterApples(apples, new ApplePredicate() { public boolean test(Apple apple) { return "red".equals(apple.getColor()); } });
到如今其实咱们的代码已经优化的很好了,实际上Java 8之前不少类库也都是这样实现的,可是这样的作法也有它的问题,那就是一长串的模板代码,阅读性也不怎么好,因此如今要轮到咱们的主角上场了,使用Lambda表达式来优化。this
List<Apple> result = filterApples(apples, (Apple apple) -> "red".equals(apple.getColor()));
到这里咱们其实咱们的目的已经实现了,可是咱们还能够再改进代码,使这个方法不局限与Apple这个里,只须要加入泛型,就能够成为一个公用的筛选方法了,筛选任意的类型数据。咱们把接口接受的参数类型改为泛型,返回的类型也改为泛型,接受的须要筛选的目标集合也改为泛型,这样就是一个能够筛选任何类型的公用方法了。线程
public interface Predicate<T> { boolean test(T t); } public static <T> List<T> filter(List<T> list, Predicate<T> p) { List<T> result = new ArrayList<>(); for (T e : list) { if (p.test(e)) { result.add(e); } } return result; }
实际上Java 8中不少自带的类库已经可使用Lambda表达式来调用了,就和咱们上面的代码同样。设计
在Java 8中List
自带了一个sort
方法,接受Comparator
(排序)类型参数,按照原来的方式就是是用匿名类,如今咱们直接用Lambda表达式。code
public interface Comparator<T> { public int compare(T o1, T o2); } //匿名类使用方式 apples.sort(new Comparator<Apple>() { public int compare(Apple a1, Apple a2){ return a1.getWeight().compareTo(a2.getWeight()); } }); //Lambda表达式 apples.sort((Apple a1, Apple a2) -> a1.getWeight().compareTo(a2.getWeight()));
同理线程也是能够这样进行改造排序
public interface Runnable{ public void run(); } //匿名方法 Thread t = new Thread(new Runnable() { public void run(){ System.out.println("Hello world"); } }); //Lambda表达式 Thread t = new Thread(() -> System.out.println("Hello world"));