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