Lambda 表達式
Lambda 表達式是 JDK8 的一個新特性,可以取代大部分的匿名內部類,寫出更優雅的 Java 代碼,尤其在集合的遍歷和其他集合操作中,可以極大地優化代碼結構。
JDK 也提供了大量的內置函數式接口供我們使用,使得 Lambda 表達式的運用更加方便、高效。
可以對某些匿名內部類的寫法進行簡化,它是函數式編程思想的一個重要體現,不用關注是什麼對象,而是更關注對數據進行了什麼操作。
基本格式
(參數列表)->{代碼}
範例
範例一:
在創建線程並啓動時可以使用匿名內部類的寫法;
- 匿名內部類方式:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread());
}
}).start();
- Lambda方式:
new Thread(() -> {
System.out.println(Thread.currentThread());
}).start();
範例二:
IntBinaryOperator是一個接口,使用匿名內部類的寫法調用該方法;
- 匿名內部類方式:
public static int calculateNum(IntBinaryOperator operator) {
int a = 10;
int b = 20;
return operator.applyAsInt(a, b);
}
@Test
public void testLambda2() {
int i = calculateNum(new IntBinaryOperator() {
@Override
public int applyAsInt(int left, int right) {
return left + right;
}
});
System.out.println(i);
}
- Lambda方式:
public static int calculateNum(IntBinaryOperator operator) {
int a = 10;
int b = 20;
return operator.applyAsInt(a, b);
}
@Test
public void testLambda2() {
int i = calculateNum((int left, int right) -> {
return left + right;
});
System.out.println(i);
}
範例三:
IntPredicate是一個接口。先使用匿名內部類的寫法調用該方法;
- 匿名內部類方式:
public static void printNum(IntPredicate predicate) {
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (int i : arr) {
if (predicate.test(i)) {
System.out.println(i);
}
}
}
@Test
public void testLambda3() {
printNum(new IntPredicate() {
@Override
public boolean test(int value) {
return value % 3 == 0;
}
});
}
- Lambda方式:
public static void printNum(IntPredicate predicate) {
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (int i : arr) {
if (predicate.test(i)) {
System.out.println(i);
}
}
}
@Test
public void testLambda3() {
printNum((int value) -> {
return value % 3 == 0;
});
}
範例四:
Function是一個接口,先使用匿名內部類的寫法調用該方法;
- 匿名內部類方式:
public static <R> R typeConver(Function<String, R> function) {
String str = "1235";
R result = function.apply(str);
return result;
}
@Test
public void testLambda4() {
Integer result = typeConver(new Function<String, Integer>() {
@Override
public Integer apply(String s) {
return Integer.valueOf(s);
}
});
System.out.println(result);
}
- Lambda方式:
public static <R> R typeConver(Function<String, R> function) {
String str = "1235";
R result = function.apply(str);
return result;
}
@Test
public void testLambda4() {
Integer result = typeConver((String s) -> {
return Integer.valueOf(s);
});
System.out.println(result);
}
範例五:
IntConsumer是一個接口,先使用匿名內部類的寫法調用該方法;
- 匿名內部類方式:
public static void foreachArr(IntConsumer consumer) {
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (int i : arr) {
consumer.accept(i);
}
}
@Test
public void testLambda5() {
foreachArr(new IntConsumer() {
@Override
public void accept(int value) {
System.out.println(value);
}
});
- Lambda方式:
public static void foreachArr(IntConsumer consumer) {
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (int i : arr) {
consumer.accept(i);
}
}
@Test
public void testLambda5() {
foreachArr((int value) -> {
System.out.println(value);
});
}
省略規則
- 參數類型可以省略;
public static void foreachArr(IntConsumer consumer) {
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (int i : arr) {
consumer.accept(i);
}
}
@Test
public void testLambda5() {
foreachArr((value) -> {
System.out.println(value);
});
}
- 方法體只有一句代碼時大括號return和唯一一句代碼的分號可以省略;
public static void foreachArr(IntConsumer consumer) {
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (int i : arr) {
consumer.accept(i);
}
}
@Test
public void testLambda5() {
foreachArr((value) -> System.out.println(value));
}
- 方法只有一個參數時小括號可以省略;
public static void foreachArr(IntConsumer consumer) {
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (int i : arr) {
consumer.accept(i);
}
}
@Test
public void testLambda5() {
foreachArr(value -> System.out.println(value));
}
- 以上這些規則都記不住也可以省略不記,可通過idea的replaceLambda表達式快速生成lambda表達式;
Stream 流
Stream將要處理的元素集合看作一種流,在流的過程中,藉助Stream API對流中的元素進行操作。
Stream - 特性
Stream可以由數組或集合創建,對流的操作分爲兩種:
- 中間操作,每次返回一個新的流,可以有多個;
- 終端操作,每個流只能進行一次終端操作,終端操作結束後流無法再次使用。終端操作會產生一個新的集合或值。
Stream特性:
-
stream不存儲數據,而是按照特定的規則對數據進行計算,一般會輸出結果;
-
stream不會改變數據源,通常情況下會產生一個新的集合或一個值;
-
stream具有延遲執行特性,只有調用終端操作時,中間操作纔會執行。
Stream - 創建方式
Stream創建方式有三種:
-
通過 java.util.Collection.stream() 方法用集合創建流;
-
使用java.util.Arrays.stream(T[] array)方法用數組創建流;
-
使用Stream的靜態方法:of()、iterate()、generate()。
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
/**
* @author hos
* @Createdate 2022/3/21 14:40
*/
public class StreamCreateType {
public static void main(String[] args) {
/**
* Stream 流的創建有3種方式
* 1. Collection.stream()方法用集合創建
* 2. Arrays.stream(T[] array) 方法用數組創建
* 3. 使用Stream的靜態方法:of()、iterate()、generate()
*/
//方式一: Collection.stream()方法用集合創建
List<String> list = Arrays.asList("1", "2", "3", "4", "5", "6", "7", "8", "9");
// 創建一個順序流
Stream<String> stream = list.stream();
// 創建一個並行流
Stream<String> stringStream = list.parallelStream();
List<String> collect = stringStream.collect(Collectors.toList());
//方式二: Arrays.stream(T[] array) 方法用數組創建
int[] array = {1, 2, 3, 4, 5};
IntStream stream1 = Arrays.stream(array);
System.out.println(stream1.max().getAsInt());
//方式三: 使用Stream的靜態方法:of()、iterate()、generate()
Stream<Integer> intStream = Stream.of(1, 2, 3, 4, 5, 6);
Stream<Integer> stream2 = Stream.iterate(0, (x) -> x + 3).limit(4);
// 0 3 6 9
stream2.forEach(System.out::println);
AtomicInteger m = new AtomicInteger(10);
Stream<Integer> stream3 = Stream.generate(()-> m.getAndIncrement()).limit(3);
//10 11 12
stream3.forEach(System.out::println);
}
}
Stream - 使用
中間操作
map
map,可以將一個流的元素按照一定的映射規則映射到另一個流中;
map,接收一個函數作爲參數,該函數會被應用到每個元素上,並將其映射成一個新的元素。
filter
filter,對流中的元素進行條件過濾,符合過濾條件的才能繼續留在流中;
filter,按照一定的規則校驗流中的元素,將符合條件的元素提取到新的流中的操作。
distinct
distinct,去除流中的重複元素;
sorted
sorted(),自然排序,流中元素需實現Comparable接口;
sorted(Comparator com),Comparator排序器自定義排序。
limit
limit,可以設置流的最大長度,超出的部分將被拋棄;
skip
skip,跳過流中的前n個元素,返回剩下的元素;
flatMap
flatMap,接收一個函數作爲參數,將流中的每個值都換成另一個流,然後把所有流連接成一個流;
map只能把一個對象轉換成另一個對象來作爲流中的元素。而flatMap可以把一個對象轉換成多個對象作爲流中的元素。
終結操作
forEach
forEach方法,通過 lambda 表達式的方式遍歷集合中的元素;
forEach,對流中的元素進行遍歷操作,通過傳入的參數去指定對遍歷到的元素進行什麼具體操作。
count
count,用來獲取當前流中元素的個數;
max&min
max&min,可以用來或者流中的最值。
collect
collect,把當前流轉換成一個集合;
collect,把一個流收集起來,最終可以是收集成一個值也可以收集成一個新的集合;流不存儲數據,那麼在流中的數據完成處理後,需要將流中的數據重新歸集到新的集合裏。
reduce
reduce,把一個流縮減成一個值,能實現對集合求和、求乘積和求最值操作;
reduce,對流中的數據按照你指定的計算方式計算出一個結果。