CF772E Verifying Kingdom - 互動、點分治
阿新 • • 發佈:2021-08-05
Java - Lambda
一.Lambda簡介
Lambda是Java 8的一個新特性,可以看做是一個匿名函式
使用Lambda表示式可以非常簡潔的對一個介面進行實現
二.Lambda對介面的要求
要求介面中抽象方法只能有一個
可使用@FunctionnalInterface將一個介面修飾為函式式介面
此時這個介面內只能有一個抽象方法,宣告多個抽象方法將會報錯
介面中的default方法不算抽象方法
三.Lambda表示式基礎語法
Lambda是一個匿名函式
引數列表 方法體
() : 描述引數列表
{} : 描述方法體
-> : Lambda運算子,讀作goes to
四.Lambda表示式語法精簡
//定義的介面 @FunctionalInterface public interface NoneReturnMultiParameter { void test(int x, int y);} @FunctionalInterface public interface NoneReturnNoneParameter { void test();} @FunctionalInterface public interface NoneReturnOneParameter { void test(int x);} @FunctionalInterface public interface OneReturnNoneParameter { int test();} @FunctionalInterface public interface OneReturnOneParameter { int test(int x);} @FunctionalInterface public interface ReturnMultiParameter { int test(int x, int y);}
//實現 ReturnMultiParameter lambda1 = (int a, int b) -> { System.out.println(a + b); return a + b; }; lambda1.test(10, 20); // 精簡1.lambda可以省略引數型別 // 但是有多個引數時,要省略引數型別必須都省略,不能一個省略,另外一個不省略 ReturnMultiParameter lambda2 = (a, b) -> { System.out.println(a + b); return a + b; }; lambda1.test(10, 20); //精簡2.當引數體中只要一個引數時,可以省略(),引數為空或有多個引數時不可省略 NoneReturnOneParameter lambda3 = a -> { System.out.println(a); }; lambda3.test(10); //精簡3.當方法體中只有一條語句時,可以省略{} NoneReturnMultiParameter lambda4 = (a, b) -> System.out.println(1); //精簡4.當方法體中只有一行返回語句時,可以省略{},但是也必須省略return語句 ReturnMultiParameter lambda5 = (a, b) -> a + b; lambda5.test(10, 20); OneReturnOneParameter lambda6 = a -> a; lambda6.test(10);
五.Lambda表示式函式引用
class Sum {
public int cal(int a, int b) {return a + b;}
}
//1.引用函式的引數數量和引數型別以及返回值型別必須和實現介面嚴格一致,不支援多型
//2.若被引用函式為靜態方法,則可通過類名::方法名引用,若不是靜態方法,則需通過 實現::方法名 引用
Sum sum = new Sum();
ReturnMultiParameter lambda = sum::cal;
System.out.println(lambda.test(10, 20));
構造方法引用
//實體類
public class Person {
public Person() {System.out.println("無參構造執行");}
public Person(String name, Integer age) {System.out.println("有參構造執行");}
}
//介面
interface PersonCreate {Person getPerson();}
interface PersonCreate2 {Person getPerson(String name, Integer age);}
// 根據介面中的引數型別和數量選擇對應的建構函式
PersonCreate lambda1 = Person::new;
Person person = lambda1.getPerson();//無參
PersonCreate2 lambda2 = Person::new;
Person person2 = lambda2.getPerson("liuyu", 18);//有參
不能訪問介面中的Default函式
NoneReturnOneParameter lambda2 = a -> {
getDouble(a);
};
十.系統內建函式式介面
Predicate<T> 引數T 返回值boolean
IntPredicate int-->boolean
LongPredicate long-->boolean
DoublePredicate double-->boolean
Consumer<T> 引數T 返回值 void
IntConsumer int --> void
LongConsumer long --> void
DoubleConsumer double --> void
Function<T, R> 引數T 返回值R
IntFunction<R> int --> R
LongFunction<R> long --> R
DoubleFunction<R> double --> R
IntToLongFunction int --> long
IntToDoubleFunction int --> double
LongToIntFunction long --> int
LongToDoubleFunction long --> double
DoubleToIntFunction double --> int
DoubleToLongFunction double --> long
Supplier<T> :引數無 返回值T
UnaryOperator<T> :引數T 返回值T
BinaryOperator<T> :引數T,T 返回值T
BiFunction<T, U, R> :引數T,U 返回值R
BiPredicate<T, U> :引數T,U 返回值boolean
BiConsumer<T, U> :引數T,U 返回值void
十一.Streams
java.util.Stream 表示了某一種元素的序列,在這些元素上可以進行各種操作。Stream操作可以是中間操作,也可以是完結操作。
完結操作會返回具體的值,而中間操作會返回流物件本身
可以通過多次呼叫同一個流操作方法將操作結果串起來(就像StringBuffer的append方法一樣)
Stream是在一個源的基礎上創建出來的,例如java.util.Collection中的list或者set(map不能作為Stream的源)
Stream操作往往可以通過順序或者並行兩種方式來執行。
可以直接通過呼叫Collections.stream()或者Collection.parallelStream()方法來建立一個流物件
例如
List<String> stringCollection = new ArrayList<>();
stringCollection.stream()
Filter(中間操作)
Filter接受一個predicate介面型別的變數,並將所有流物件中的元素進行過濾
ForEach(完結操作)
ForEach接受一個function介面型別的變數,用來執行對每一個元素的操作
stringCollection
.stream()
.filter((s) -> s.startsWith("a"))
.forEach(System.out::println);
Sorted(中間操作)
返回一個排過序的流物件的檢視。流物件中的元素會按照自然順序進行排序,也可由你自己指定一個Comparator介面來改變排序規則
注:
sorted只是建立一個流物件排序的檢視,而不會改變原來集合中元素的順序。原來集合中的元素順序是沒有改變的
Map(中間操作)
通過給定的方法,能夠把流物件中的每一個元素對應到另一個物件上。下面的例子就演示瞭如何把每個string都轉換成大寫的string.
不但如此,你還可以把每一種物件對映成為其他型別。對於帶泛型結果的流物件,具體的型別還要由傳遞給map的泛型方法來決定。
stringCollection
.stream()
.map(String::toUpperCase)
.sorted((a, b) -> b.compareTo(a))
.forEach(System.out::println);
Match(終結操作)
匹配操作有多種不同的型別,都是判斷某一種規則是否與流物件相吻合
所有的匹配操作都是終結操作,只返回一個boolean型別的結果
//List<String> stringCollection = new ArrayList<>();
boolean anyStartsWithA =
stringCollection
.stream()
.anyMatch((s) -> s.startsWith("a"));
System.out.println(anyStartsWithA); // true
boolean allStartsWithA = stringCollection
.stream()
.allMatch((s) -> s.startsWith("a"));
System.out.println(allStartsWithA); // false
boolean noneStartsWithZ = stringCollection
.stream()
.noneMatch((s) -> s.startsWith("z"));
System.out.println(noneStartsWithZ); // true
Count(完結操作)
返回一個數值,標識當前流物件中包含的元素數量
long startsWithB =
stringCollection
.stream()
.filter((s) -> s.startsWith("b"))
.count();
System.out.println(startsWithB); // 3
Reduce(完結操作)
通過某一個方法,對元素進行削減操作。操作的結果會放在一個Optional變數中返回
Optional<String> reduced =
stringCollection
.stream()
.sorted()
.reduce((s1, s2) -> s1 + "#" + s2);
Parallel Streams
流操作可以是順序的,也可以是並行的。順序操作通過單執行緒執行,而並行操作則通過多執行緒執行
//序列排序
long count = values.stream().sorted().count();
//並行排序
long count = values.parallelStream().sorted().count();
十一.閉包
int num = 10
Consumer<Integer> consumer = (a) -> {
System.out.println(num);
System.out.println(++num);//會報錯
};
++num; //會報錯
consumer.accept(20);
//當lambda引用區域性變數時,此變數會自動被編譯器加上final修飾,在任何地方都不能對變數進行修改