Java 8之Lambda表達式實際應用

前面 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);
}
  1. 假設咱們如今有個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;
    }
  2. 通過咱們的改進,把要篩選的顏色也看成參數傳進來方法,這樣想選什麼樣顏色就選什麼顏色,可是需求永遠都是會變得,若是說除了顏色還要再加上重量做爲篩選呢?因此咱們又對代碼進行了改進。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;
    }
  3. 既然要加多重量做爲篩選條件,那乾脆把重量也看成參數傳進去,這個時候咱們發現這段代碼開始變得很噁心了,在項目很趕的時候不少人會寫出相似這種代碼,需求是實現了,可是幾乎沒有什麼閱讀性可言,並且最多過一個星期,連你本身均可能看不懂本身寫的什麼東西,並且若是代碼沒有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;
    }
  4. 如今封裝方法的方式已經沒辦法很好的解決問題了,因此咱們決定使用設計模式中的策略模式解決這個問題,咱們新建一個接口,裏面定義一個方法接受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());
        }
    });
  5. 到如今其實咱們的代碼已經優化的很好了,實際上Java 8之前不少類庫也都是這樣實現的,可是這樣的作法也有它的問題,那就是一長串的模板代碼,閱讀性也不怎麼好,因此如今要輪到咱們的主角上場了,使用Lambda表達式來優化。this

    List<Apple> result = filterApples(apples, (Apple apple) -> "red".equals(apple.getColor()));
  6. 到這裏咱們其實咱們的目的已經實現了,可是咱們還能夠再改進代碼,使這個方法不侷限與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自帶類庫使用Lambda表達式:

實際上Java 8中不少自帶的類庫已經可使用Lambda表達式來調用了,就和咱們上面的代碼同樣。設計

  1. 在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()));
  2. 同理線程也是能夠這樣進行改造排序

    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"));
相關文章
相關標籤/搜索