前面 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"));