JDK8 - Lambda 表達式


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具有延遲執行特性,只有調用終端操作時,中間操作才會執行。

image-20220321145135117

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()
         *      - 數組: Arrays.stream(數組) 或 Stream.of
         *      - 雙列集合: 轉換成單列集合后再創建
         */
        //單列集合: 集合對象.stream()
        List<String> listStr = new ArrayList<>();
        Stream<String> stream4 = listStr.stream();

        //數組: Arrays.stream(數組) 或 Stream.of
        Integer[] arr = {1,2,3,4,5};
        Stream<Integer> stream5 = Arrays.stream(arr);
        Stream<Integer> stream6 = Stream.of(arr);

        //雙列集合: 轉換成單列集合后再創建
        Map<String,Integer> map = new HashMap<>();
        map.put("hos",19);
        map.put("hosys",17);
        map.put("hosystem",16);
        Stream<Map.Entry<String, Integer>> stream7 = map.entrySet().stream();
    }
}

Stream - 使用

中間操作

map

map,可以將一個流的元素按照一定的映射規則映射到另一個流中;

map,接收一個函數作為參數,該函數會被應用到每個元素上,並將其映射成一個新的元素。

//Stream - map: 可以將一個流的元素按照一定的映射規則映射到另一個流中
Integer[] arr = {1, 2, 3, 4, 5};
//Arrays.stream創建流
Arrays.stream(arr).map(element -> element + 10).forEach(System.out::println);
filter

filter,對流中的元素進行條件過濾,符合過濾條件的才能繼續留在流中;

filter,按照一定的規則校驗流中的元素,將符合條件的元素提取到新的流中的操作。

//Stream - filter: 對流中的元素進行條件過濾
Integer[] arr = {1, 2, 3, 4, 5};
//Arrays.stream創建流
//打印數組中大於3的元素
Arrays.stream(arr).filter(arrElement -> arrElement > 3).forEach(System.out::println);
distinct

distinct,去除流中的重復元素;

注意: distinct方法是依賴Object的equals方法來判斷是否是相同對象的,所以需要注意重寫equals方法;

//Stream - distinct: 去除重復元素
Integer[] arr = {1, 2, 2, 3, 3, 4, 4, 5};
//Arrays.stream創建流
//去除重復元素
Arrays.stream(arr).distinct().forEach(System.out::println);
sorted

sorted(),自然排序,流中元素需實現Comparable接口;

sorted(Comparator com),Comparator排序器自定義排序。

注意: 如果調用空參的sorted()方法,需要流中的元素是實現了Comparable。

//Stream - sorted: 自然排序
Integer[] arr = {5,4, 3, 2, 1};
//Arrays.stream創建流
Arrays.stream(arr).sorted().forEach(System.out::println);
limit

limit,可以設置流的最大長度,超出的部分將被拋棄;

//Stream - limit: 設置流的最大長度
Integer[] arr = {1, 2, 3, 4, 5};
//Arrays.stream創建流
Arrays.stream(arr).limit(2).forEach(System.out::println);
skip

skip,跳過流中的前n個元素,返回剩下的元素;

//Stream - skip: 跳過流中的前n個元素
Integer[] arr = {1, 2, 3, 4, 5};
//Arrays.stream創建流
Arrays.stream(arr).skip(2).forEach(System.out::println);
flatMap

flatMap,接收一個函數作為參數,將流中的每個值都換成另一個流,然后把所有流連接成一個流;

map只能把一個對象轉換成另一個對象來作為流中的元素。而flatMap可以把一個對象轉換成多個對象作為流中的元素。

//Stream - flatMap: 接收一個函數作為參數,將流中的每個值都換成另一個流
ArrayList<Object> list = new ArrayList<>();
ArrayList<Object> list1 = new ArrayList<>();
ArrayList<Object> list2 = new ArrayList<>();
ArrayList<Object> list3 = new ArrayList<>();
ArrayList<Object> list4 = new ArrayList<>();
ArrayList<Object> list5 = new ArrayList<>();

list1.add("str1");
list2.add("str2");
list3.add("str3");
list4.add("str4");
list5.add("str5");
list.add(list1);
list.add(list2);
list.add(list3);
list.add(list4);
list.add(list5);

list.stream().flatMap(o -> Stream.of(o)).forEach(System.out::println);

終結操作

forEach

forEach方法,通過 lambda 表達式的方式遍歷集合中的元素;

forEach,對流中的元素進行遍歷操作,通過傳入的參數去指定對遍歷到的元素進行什么具體操作。

//Stream - forEach: 通過 lambda 表達式的方式遍歷集合中的元素
Integer[] arr = {1, 2, 3, 4, 5};
//Arrays.stream創建流
Arrays.stream(arr).forEach(System.out::println);
count

count,用來獲取當前流中元素的個數;

//Stream - count: 用來獲取當前流中元素的個數
Integer[] arr = {1, 2, 3, 4, 5};
//Arrays.stream創建流
System.out.println(Arrays.stream(arr).count());
max&min

max&min,可以用來或者流中的最值。

//Stream - max&min: 可以用來或者流中的最值
Integer[] arr = {1, 2, 3, 4, 5};
//Arrays.stream創建流
System.out.println(Arrays.stream(arr).max((o1, o2) -> o1 - o2).get());
System.out.println(Arrays.stream(arr).min((o1, o2) -> o1 - o2).get());
collect

collect,把當前流轉換成一個集合;

collect,把一個流收集起來,最終可以是收集成一個值也可以收集成一個新的集合;流不存儲數據,那么在流中的數據完成處理后,需要將流中的數據重新歸集到新的集合里。

//Stream - collect: 把當前流轉換成一個集合
Integer[] arr = {1, 2, 3, 4, 5};
//Arrays.stream創建流
//收集大於3且放到list集合中
List<Integer> collect = Arrays.stream(arr).filter(ele -> ele > 3).collect(Collectors.toList());
System.out.println(collect);
reduce

reduce,把一個流縮減成一個值,能實現對集合求和、求乘積和求最值操作;

reduce,對流中的數據按照你指定的計算方式計算出一個結果。

//Stream - reduce: 對流中的數據按照你指定的計算方式計算出一個結果
Integer[] arr = {1, 2, 3, 4, 5};
//Arrays.stream創建流
Integer addSum = Arrays.stream(arr).reduce(1, (result, element) -> result + element);
Integer subSum = Arrays.stream(arr).reduce(1, (result, element) -> result - element);
Integer mulSum = Arrays.stream(arr).reduce(1, (result, element) -> result * element);
Integer divSum = Arrays.stream(arr).reduce(120, (result, element) -> result / element);
System.out.println(addSum);
System.out.println(subSum);
System.out.println(mulSum);
System.out.println(divSum);


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM