java8新特性之Lambda表達式

​ java8在2014年就推出了,成天喊着8版本穩定,企業都用jdk8,結果8的特性如今才系統的學,罪過罪過啊!此係列博客可能3-4篇,帶你全面地瞭解java8新特性。java

​ 其實我日常學習的時候看某些入門博客,總擔憂寫的不全,因此但願本身之後寫的技術博客可以把必須的儘量全的總結出來,作到看一篇就可以入門的水平。app

lambda快速體驗

​ 入門最快就是看demo啦,如今有個需求,讓你在衆多蘋果中挑選出紅色的蘋果ide

  • 蘋果類函數

    public class Apple {
        String color;
        int weight;
        //省略構造函數,get方法
    }

寫法1:

public static List<Apple> filterGreenAppleWithNormal(List<Apple> apples) {
    List<Apple> res = new ArrayList<>();
    for (Apple apple : apples) {
        if ("red".equals(apple.getColor())) {
            res.add(apple);
        }
    }
    return res;
}

//調用
List<Apple> normal = filterGreenAppleWithNormal(apples);

​ 若是再有一個需求說挑選出綠色的蘋果呢,按照這種寫法就須要建立一個新的類,而後僅僅把"red" 修改爲"green" 其它都不變,這明顯是不顯示的。因此能夠把顏色當成參數傳進去學習

寫法2:

public static List<Apple> filterGreenAppleWithArg(List<Apple> apples, String color) {
    List<Apple> res = new ArrayList<>();
    for (Apple apple : apples) {
        if (color.equals(apple.getColor())) {
            res.add(apple);
        }
    }
    return res;
}

//調用
List<Apple> arg = filterGreenAppleWithArg(apples, "red");

​ 此時再有一個需求,須要篩選出必定重量或者某個顏色的蘋果,須要怎麼辦呢,按照上述想法是把能想到的屬性都堆到方法的參數中。ui

public static List<Apple> filterWeightOrColorWithArg(List<Apple> apples, String color, int weight, boolean flag) {
    List<Apple> res = new ArrayList<>();

    for (Apple apple : apples) {
        if (flag && color.equals(apple.getColor()) || !flag && apple.getWeight() > weight) {
            res.add(apple);
        }
    }
    return res;
}

//調用
List<Apple> weightOrColor = filterWeightOrColorWithArg(apples, "", 500, false);

​ 能夠這樣寫嗎,固然能夠解決問題,可是若是有5個屬性呢,6個屬性呢,還有,參數中的flag是什麼意思呢。idea

​ 仔細一想,篩選顏色,篩選重量,這些的本質是在篩選,是一個行爲(後面更專業稱謂語),能夠把行爲抽象成一個接口spa

  • 行爲接口
public interface AppleFilter {
    boolean filter(Apple apple);
}

寫法3:

​ 首先須要實現這個接口來具體化行爲code

  • 篩選紅色蘋果實現類
public class RedFilter implements AppleFilter {
    @Override
    public boolean filter(Apple apple) {
        return "red".equals(apple.getColor());
    }
}

​ 回到使用orm

public static List<Apple> filterApples(List<Apple> apples, AppleFilter filter) {
    List<Apple> res = new ArrayList<>();

    for (Apple apple : apples) {
        if (filter.filter(apple)) {
            res.add(apple);
        }
    }

    return res;
}

//調用
List<Apple> behavior = filterApples(apples, new GreenFilter());

​ 這樣看就舒服多了,當有新需求的時候,只須要再添加一個類,好比需求是篩選出重量超200g的蘋果,只須要新建一個篩選類實現上述接口便可。

public class WeightGt200Filter implements AppleFilter {
    @Override
    public boolean filter(Apple apple) {
        return apple.getWeight() > 200;
    }
}

​ 還能怎樣精簡代碼呢?熟悉Java的小夥伴到這裏應該就想到了匿名內部類

寫法4:

List<Apple> innerClass = filterApples(apples, new AppleFilter() {
    @Override
    public boolean filter(Apple apple) {
        return "green".equals(apple.getColor());
    }
});

​ 通常到這一步,比較不錯的IDE就會開始提醒建議了

image-20210413193608641

​ 這就到了咱們今天的重點,lambda表達式

寫法5:

List<Apple> lambda = filterApples(apples, apple -> apple.getWeight() > 500);

​ 沒錯,就是這麼精簡,不過filterApples 這個方法是不能省略的,可是擴展性相較1,2,簡潔性相較3,4都好了不少

什麼是lambda

能夠把Lamdba表達式理解爲簡潔地表示可傳遞的匿名函數的一種形式:它沒有名稱,但它有 參數列表、函數主題、返回類型,可能還有一個能夠拋出的異常列表

書寫格式: (參數) -> {主體}

​ 正如上面寫法5同樣(apple) -> {apple.getWeight() > 500;}

  • lambda表達式對參數可以自動推斷類型,固然也能夠顯示書寫類型
  • 沒有return語句,應爲已經有隱含了return
  • lambda中能夠有多行語句

使用案例:

  • () -> {}
  • () -> "java"
  • () -> {return "java";}
  • (int a, int b) -> a * b
  • () -> {System.out.println("hello"); System.out.println("java");}

如何才能使用lambda

使用 函數式接口的時候才能使用lambda表達式

​ 所謂函數式接口就是僅僅定義了一個抽象方法,好比一開始把行爲抽象成一個AppleFilter 接口,該接口只有一個filter() 方法。注意是隻有一個抽象方法,並非只有一個方法,通俗來講是繼承該接口的類只須要實現一個方法。

​ 最多見的兩個接口是ComparatorRunnable

image-20210413200933737

​ 後來爲了更方便地區分函數式接口,Java新的API中多了一個@FuntionalInterface ,該註解僅僅是代表該類是函數式接口(並非必須的),若是有該註解的同時聲明瞭兩個抽象方法,那麼將會報錯

image-20210413201531957

java.util.function下4個經常使用的函數式接口

java.util.function 下主要有4個經常使用的函數式接口,FunctionPredicateConsumerPredicate ,隨便截取其中的一個源碼片斷來看,其實也沒啥好看的

image-20210413202124036

​ 對這些函數式接口也是得看接口是如何聲明的,這裏就拿Predicate 舉例,該接口主要是對傳進來的對象進行一個處理,而後返回boolean 值。是否是有點熟悉,沒錯,就是和篩選蘋果同樣

  • predicateDemo
public static List<Apple> predicateDemo(List<Apple> apples, Predicate<Apple> predicate) {
    List<Apple> res = new ArrayList<>();
    for (Apple apple : apples) {
        if (predicate.test(apple)) {
            res.add(apple);
        }
    }
    return res;
}

//調用
List<Apple> predicate = predicateDemo(apples, apple -> "green".equals(apple.getColor()));

​ 其餘的也是同理,上才藝

  • functionDemo
public static List<Integer> functionDemo(List<Integer> nums, Function<Integer, Integer> function) {
    List<Integer> res = new ArrayList<>();
    for (int num : nums) {
        res.add(function.apply(num));
    }
    return res;
}

//調用
List<Integer> function = functionDemo(Arrays.asList(1, 8, 7, 3, 9, 2), (num) -> num * 2);
  • consumerDemo
public static void consumerDemo(List<Integer> list, Consumer<Integer> consumer) {
    for (int num : list) {
        consumer.accept(num);
    }
}

//調用
consumerDemo(Arrays.asList(1, 5, 6), (num) -> System.out.println(num));
consumerDemo(Arrays.asList(1, 5, 6), System.out::println);
  • supplierDemo
public static void supplierDemo(List<Integer> nums, Supplier<String> supplier) {
    StringBuilder sb = new StringBuilder();
    for (int num : nums) {
        sb.append(num).append(supplier.get());
    }
    System.out.println(sb);
}

//調用
supplierDemo(Arrays.asList(1, 5, 6), ()->"java");

方法引用

​ 上面的lambda寫法是最精簡的嗎,不,不是的,還有最最最精簡的寫法,那就是利用方法引用

​ 方法引用主要有3類:

  • 指向靜態方法的方法引用
Comparator<Integer> normalComparator = (a, b) -> a.compareTo(b);
Comparator<Integer> referenceComparator = Integer::compareTo;
  • 指向任一類型實例方法的方法引用
Function<String, Integer> normalFunction = (str) -> str.length();
Function<String, Integer> referenceFunction = String::length;

BiPredicate<List<String>, String> normalPredicate = (strings, str) -> strings.contains(str);
BiPredicate<List<String>, String> referencePredicate = List::contains;
  • 指向現有對象的實例方法引用
Apple apple = new Apple();
Supplier<Integer> normal = () -> apple.getWeight();
Supplier<Integer> reference = apple::getWeight;
  • 固然也能夠用於構造函數
Supplier<Apple> normalSupplier = () -> new Apple();
Supplier<Apple> referenceSupplier = Apple::new;

總結

​ 以上就是java8中的lambda表達式,還有一些知識點是沒有講的,可是以爲不是特別必須,好比類型推斷是怎麼推斷的,還有Lambda複合,拋出異常,拆箱裝箱一樣沒有講。而後一些東西也不是全盤托出,須要各位小夥伴去idea中進入到源碼觀看。

相關文章
相關標籤/搜索