1. 程式人生 > >Java語法進階16-Lambda-Stream-Optional

Java語法進階16-Lambda-Stream-Optional

Lambda

  大年初二,大門不出二門不邁。繼續學習!

函式式介面

  Lambda表示式其實就是實現SAM介面的語法糖,所謂SAM介面就是Single Abstract Method,即該介面中只有一個抽象方法需要實現,當然該介面可以包含其他非抽象方法。

   它關注方法具備什麼樣的功能,強調做什麼,而不是以什麼形式做。

  • 面向物件的思想:

    • 做一件事情,找一個能解決這個事情的物件,呼叫物件的方法,完成事情.

  • 函數語言程式設計思想:

    • 只要能獲取到結果,誰去做的,怎麼做的都不重要,重視的是結果,不重視過程

自定義函式式介面

   只要確保介面中有且僅有一個抽象方法即可

修飾符 interface 介面名稱 {
    public abstract 返回值型別 方法名稱(可選引數資訊);// public abstract 是可以省略的
    // 其他非抽象方法內容
}

消費型介面

  消費型介面的抽象方法特點:有形參,但是返回值型別是void

介面名抽象方法描述
Consumer<T> void accept(T t) 接收一個物件用於完成功能
BiConsumer<T,U> void accept(T t, U u) 接收兩個物件用於完成功能
DoubleConsumer void accept(double value) 接收一個double值
IntConsumer void accept(int value) 接收一個int值
LongConsumer void accept(long value) 接收一個long值
ObjDoubleConsumer<T> void accept(T t, double value) 接收一個物件和一個double值
ObjIntConsumer<T> void accept(T t, int value) 接收一個物件和一個int值
ObjLongConsumer<T> void accept(T t, long value) 接收一個物件和一個long值

供給型介面

  供給型介面的抽象方法特點:無參,但是有返回值

介面名抽象方法描述
Supplier<T> T get() 返回一個物件
BooleanSupplier boolean getAsBoolean() 返回一個boolean值
DoubleSupplier double getAsDouble() 返回一個double值
IntSupplier int getAsInt() 返回一個int值
LongSupplier long getAsLong() 返回一個long值

判斷型介面

  判斷型介面的抽象方法特點:有參,但是返回值型別是boolean結果

介面名抽象方法描述
Predicate<T> boolean test(T t) 接收一個物件
BiPredicate<T,U> boolean test(T t, U u) 接收兩個物件
DoublePredicate boolean test(double value) 接收一個double值
IntPredicate boolean test(int value) 接收一個int值
LongPredicate boolean test(long value) 接收一個long值

功能型介面

  功能型介面的抽象方法特點:既有引數又有返回值

介面名抽象方法描述
Function<T,R> R apply(T t) 接收一個T型別物件,返回一個R型別物件結果
UnaryOperator<T> T apply(T t) 接收一個T型別物件,返回一個T型別物件結果
DoubleFunction<R> R apply(double value) 接收一個double值,返回一個R型別物件
IntFunction<R> R apply(int value) 接收一個int值,返回一個R型別物件
LongFunction<R> R apply(long value) 接收一個long值,返回一個R型別物件
ToDoubleFunction<T> double applyAsDouble(T value) 接收一個T型別物件,返回一個double
ToIntFunction<T> int applyAsInt(T value) 接收一個T型別物件,返回一個int
ToLongFunction<T> long applyAsLong(T value) 接收一個T型別物件,返回一個long
DoubleToIntFunction int applyAsInt(double value) 接收一個double值,返回一個int結果
DoubleToLongFunction long applyAsLong(double value) 接收一個double值,返回一個long結果
IntToDoubleFunction double applyAsDouble(int value) 接收一個int值,返回一個double結果
IntToLongFunction long applyAsLong(int value) 接收一個int值,返回一個long結果
LongToDoubleFunction double applyAsDouble(long value) 接收一個long值,返回一個double結果
LongToIntFunction int applyAsInt(long value) 接收一個long值,返回一個int結果
DoubleUnaryOperator double applyAsDouble(double operand) 接收一個double值,返回一個double
IntUnaryOperator int applyAsInt(int operand) 接收一個int值,返回一個int結果
LongUnaryOperator long applyAsLong(long operand) 接收一個long值,返回一個long結果
     
BiFunction<T,U,R> R apply(T t, U u) 接收一個T型別和一個U型別物件,返回一個R型別物件結果
BinaryOperator<T> T apply(T t, T u) 接收兩個T型別物件,返回一個T型別物件結果
ToDoubleBiFunction<T,U> double applyAsDouble(T t, U u) 接收一個T型別和一個U型別物件,返回一個double
ToIntBiFunction<T,U> int applyAsInt(T t, U u) 接收一個T型別和一個U型別物件,返回一個int
ToLongBiFunction<T,U> long applyAsLong(T t, U u) 接收一個T型別和一個U型別物件,返回一個long
DoubleBinaryOperator double applyAsDouble(double left, double right) 接收兩個double值,返回一個double結果
IntBinaryOperator int applyAsInt(int left, int right) 接收兩個int值,返回一個int結果
LongBinaryOperator long applyAsLong(long left, long right) 接收兩個long值,返回一個long結果

Lambda表示式語法

  其本質上,Lambda表示式是用於實現【函式式介面】的“抽象方法”

Lambda表示式語法格式

(形參列表) -> {Lambda體}

說明:

  • (形參列表)它就是你要賦值的函式式介面的抽象方法的 (形參列表),照抄

  • {Lambda體}就是實現這個抽象方法的方法體

  • -> 稱為Lambda操作符(減號和大於號中間不能有空格,而且必須是英文狀態下半形輸入方式)

優化:Lambda表示式可以精簡

  • 當{Lambda體}中只有一句語句時,可以省略{}和{;}

  • 當{Lambda體}中只有一句語句時,並且這個語句還是一個return語句,那麼return也可以省略,但是如果{;}沒有省略的話,return是不能省略的

  • (形參列表)的型別可以省略

  • 當(形參列表)的形參個數只有一個,那麼可以把資料型別和()一起省略,但是形參名不能省略

  • 當(形參列表)是空參時,()不能省略

ArrayList<String> list = new ArrayList<>();
list.forEach((li) -> System.out.println("li = " + li));//void forEach(Consumer<? super T> action)

方法引用

  當 Lambda 體滿足一些特殊的情況時,還可以再簡化

    (1)Lambda體只有一句語句,並且是通過呼叫一個物件的/類的現有的方法來完成的

    (2)並且Lambda表示式的形參正好是給該方法的實參

  方法引用的語法格式:

    (1)例項物件名::例項方法

    (2)類名::靜態方法

    (3)類名::例項方法

  說明:

    :: 稱為方法引用操作符(兩個 : 中間不能有空格,而且必須英文狀態下半形輸入)

    Lambda表示式的形參列表,全部在Lambda體中使用上了,要麼是作為呼叫方法的物件,要麼是作為方法的實參。

    在整個Lambda體中沒有額外的資料。

構造器引用

  (1)當Lambda表示式是建立一個物件,並且滿足Lambda表示式形參,正好是給建立這個物件的構造器的實參列表。

  (2) 當Lambda表示式是建立一個數組物件,並且滿足Lambda表示式形參,正好是給建立這個陣列物件的長度

  構造器引用的語法格式:

    類名::new

    陣列型別名::new

Stream

  Stream API 提供了一種高效且易於使用的處理資料的方式。

  Stream 是 Java8 中處理集合的關鍵抽象概念,它可以指定你希望對集合進行的多種操作,可以執行非常複雜的查詢、過濾和對映資料等操作。

  Stream 是資料渠道,用於操作資料來源(集合、陣列等)所儲存的元素序列。“集合指的是負責儲存資料,Stream流指的是計算,負責處理資料!”

注意:

  ①Stream 自己不會儲存元素。

  ②Stream 不會改變源物件。每次處理都會返回一個持有結果的新Stream。

  ③Stream 操作是延遲執行的。這意味著他們會等到需要結果的時候才執行。

Stream 的操作三個步驟:

  1- 建立 Stream:通過一個數據源(如:集合、陣列),獲取一個流

  2- 中間操作:中間操作是個操作鏈,對資料來源的資料進行n次處理,但是在終結操作前,並不會真正執行。

  3- 終止操作:一旦執行終止操作,就執行中間操作鏈,最終產生結果並結束Stream。

建立Stream

  1、建立 Stream方式一:通過集合

    Java8 中的 Collection 介面被擴充套件,提供了兩個獲取流的方法:

      public default Stream<E> stream() : 返回一個順序流

      public default Stream<E> parallelStream() : 返回一個並行流

  2、建立 Stream方式二:通過陣列

    Java8 中的 Arrays 的靜態方法 stream() 可以獲取陣列流:

      public static <T> Stream<T> stream(T[] array): 返回一個流

     還有過載形式,能夠處理對應基本型別的陣列

  3、建立 Stream方式三:通過 Stream.of()

    可以呼叫Stream類靜態方法 of(), 通過顯示值建立一個流。它可以接收任意數量的引數。

      public static<T> Stream<T> of(T... values) : 返回一個順序流

  4、建立 Stream方式四:建立無限流

    可以使用靜態方法 Stream.iterate() 和 Stream.generate(), 建立無限流。

      public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f):返回一個無限流

      public static<T> Stream<T> generate(Supplier<T> s) :返回一個無限流

中間操作

  多箇中間操作可以連線起來形成一個流水線,除非流水線上觸發終止操作,否則中間操作不會執行任何的處理!而在終止操作時一次性全部處理,稱為“惰性求值”。

方 法描 述
filter(Predicate p) 篩選,接收 Lambda , 從流中排除某些元素
distinct() 去除,通過流所生成元素的equals() 去除重複元素
limit(long maxSize) 截斷流,使其元素不超過給定數量
skip(long n) 跳過元素,返回一個扔掉了前 n 個元素的流。若流中元素不足 n 個,則返回一個空流。與 limit(n) 互補
peek(Consumer action) 接收Lambda,對流中的每個資料執行Lambda體操作
sorted() 產生一個新流,其中按自然順序排序
sorted(Comparator com) 產生一個新流,其中按比較器順序排序
map(Function f) 接收一個函式作為引數,該函式會被應用到每個元素上,並將其對映成一個新的元素。
mapToDouble(ToDoubleFunction f) 接收一個函式作為引數,該函式會被應用到每個元素上,產生一個新的 DoubleStream。
mapToInt(ToIntFunction f) 接收一個函式作為引數,該函式會被應用到每個元素上,產生一個新的 IntStream。
mapToLong(ToLongFunction f) 接收一個函式作為引數,該函式會被應用到每個元素上,產生一個新的 LongStream。
flatMap(Function f) 接收一個函式作為引數,將流中的每個值都換成另一個流,然後把所有流連線成一個流

終結操作

  終端操作會從流的流水線生成結果。其結果可以是任何不是流的值,例如:List、Integer,甚至是 void。流進行了終止操作後,不能再次使用。

方法描述
boolean allMatch(Predicate p) 檢查是否匹配所有元素
boolean anyMatch(Predicate p) 檢查是否至少匹配一個元素
boolean noneMatch(Predicate p) 檢查是否沒有匹配所有元素
Optional<T> findFirst() 返回第一個元素
Optional<T> findAny() 返回當前流中的任意元素
long count() 返回流中元素總數
Optional<T> max(Comparator c) 返回流中最大值
Optional<T> min(Comparator c) 返回流中最小值
void forEach(Consumer c) 迭代
T reduce(T iden, BinaryOperator b) 可以將流中元素反覆結合起來,得到一個值。返回 T
U reduce(BinaryOperator b) 可以將流中元素反覆結合起來,得到一個值。返回 Optional<T>
R collect(Collector c) 將流轉換為其他形式。接收一個 Collector介面的實現,用於給Stream中元素做彙總的方法

  Collector 介面中方法的實現決定了如何對流執行收集的操作(如收集到 List、Set、Map)。另外, Collectors 實用類提供了很多靜態方法,可以方便地建立常見收集器例項。

Optional<T>

  為了解決空指標異常,Optional 提供很多有用的方法,這樣我們就不用顯式進行空值檢測。

  Optional實際上是個容器:它可以儲存型別 T 的值,或者僅僅儲存 null。

API

  1、如何建立Optional物件?或者說如何用Optional來裝值物件或null值

    (1)static <T> Optional<T> empty() :用來建立一個空的Optional

    (2)static <T> Optional<T> of(T value) :用來建立一個非空的Optional

    (3)static <T> Optional<T> ofNullable(T value) :用來建立一個可能是空,也可能非空的Optional

  2、如何從Optional容器中取出所包裝的物件呢?

    (1)T get() :要求Optional容器必須非空

        T get()與of(T value)使用是安全的

    (2)T orElse(T other) :

        orElse(T other) 與 ofNullable(T value)配合使用,

        如果Optional容器中非空,就返回所包裝值,如果為空,就用orElse(T other)other指定的預設值(備胎)代替

    (3)T orElseGet(Supplier<? extends T> other) :

        如果Optional容器中非空,就返回所包裝值,如果為空,就用Supplier介面的Lambda表示式提供的值代替

    (4)<X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier)

        如果Optional容器中非空,就返回所包裝值,如果為空,就丟擲你指定的異常型別代替原來的NoSuchElementException

  3、其他方法

    (1)boolean isPresent() :判斷Optional容器中的值是否存在

    (2)void ifPresent(Consumer<? super T> consumer) :

        判斷Optional容器中的值是否存在,如果存在,就對它進行Consumer指定的操作,如果不存在就不做

    (3)<U> Optional<U> map(Function<? super T,? extends U> mapper)

        判斷Optional容器中的值是否存在,如果存在,就對它進行Function介面指定的操作,如果不存在就不做

重要的一點是 Optional 不是 Serializable。因此,它不應該用作類的欄位。

 Jackson 庫支援把 Optional 當作普通物件。也就是說,Jackson 會把空物件看作 null,而有值的物件則把其值看作對應域的值。

&n