Java:Java8新特性

1. Lambda表達式

1.1 Lambda表達式的好處

Lambda 是一個匿名函數,我們可以把 Lambda 表達式理解為是一段可以傳遞的代碼(將代碼像數據一樣進行傳遞)

使用它可以寫出更簡潔、更靈活的代碼。作為一種更緊湊的代碼風格,使Java的語言表達能力得到了提升

Lambda表達式的本質是:作為函數式接口的實例

1.2 Lambda表達式舉例

//導入的包有;import org.junit.Test;import java.util.Comparator;

public class LambdaTest1 {
    @Test
    public void test1(){
        Runnable r1 = new Runnable(){
            @Override
            public void run() {
                System.out.println("我愛北京天安門");
            }
        };
        r1.run();

        //Lambad表達式寫法
        Runnable r2 = () -> System.out.println("我愛北京天安門");
        r2.run();
    }
    @Test
    public void test2(){
        Comparator<Integer> com1 = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return Integer.compare(o1,o2);
            }
        };
        int compare1 = com1.compare(12,21);
        System.out.println(compare1);

        //Lambda表達式
        Comparator<Integer> com2 = (o1,o2) ->Integer.compare(o1,o2);
        int compare2 = com2.compare(12,21);
        System.out.println(compare2);

        //方法引用
        Comparator<Integer> com3 = Integer :: compare;
        int compare3 = com3.compare(12,21);
        System.out.println(compare3);
    }
}

1.3 Lambda表達式的使用

舉例:(o1,o2) -> Integer.compare(o1,o2)

格式

  • ->:Lambda操作符或箭頭操作符
  • ->左邊:Lambda形參列表(其實就是接口中的抽象方法的形參列表)
  • ->右邊:Lambda體(其實就是重寫的抽象方法的方法體)

語法格式

  1. 語法格式一:無參,無返回值
  1. 語法格式二:Lambda需要一個參數,但是沒有返回值
  1. 語法格式三:數據類型可以省略,因為可由編譯器推斷得出,稱為“類型推斷”
  1. 語法格式四:Lambda若只需要一個參數時,參數的小括號可以省略
  1. 語法格式五:Lambda需要兩個或以上的參數,多條執(zhí)行語句,并且可以有返回值
  1. 語法格式六:當Lambda體只有一條語句時,return與大括號若有,都可以省略

總的來說,語法格式為

  • ->左邊:lambda形參列表的參數類型可以省略(類型推斷),如果形參列表只有一個參數,其一對()也可省略
  • ->右邊:lambda體應該使用一對{}包裹,如果lambda體只有一條執(zhí)行語句(可能是return語句),省略這一對{}和return關鍵字
//導入的包有:import org.junit.Test;import java.util.Comparator;import java.util.function.Consumer;

public class LambdaTest2 {
    @Test
    public void test1(){
        //語法格式一:無參,無返回值
        Runnable r1 = new Runnable(){
            @Override
            public void run() {
                System.out.println("我愛北京天安門");
            }
        };
        r1.run();

        System.out.println("***************************");

        //Lambad表達式寫法
        Runnable r2 = () -> {
            System.out.println("我愛北京天安門");
        };
        r2.run();
    }
    @Test
    public void test2(){
        //語法格式二:Lambda需要一個參數,但是沒有返回值
        Consumer<String> con = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        con.accept("今天是個好日子");

        System.out.println("***************************");

        Consumer<String> con1 = (String s) -> {
            System.out.println(s);
        };
        con1.accept("今天是個好日子");
    }
    @Test
    public void test3(){
        //語法格式三:數據類型可以省略,因為可由編譯器推斷得出,稱為“類型推斷”
        Consumer<String> con1 = (String s) -> {
            System.out.println(s);
        };
        con1.accept("今天是個好日子");

        System.out.println("***************************");

        Consumer<String> con2 = (s) -> {
            System.out.println(s);
        };
        con2.accept("今天是個好日子");
    }
    @Test
    public void test4(){
        //語法格式四:Lambda若只需要一個參數時,參數的小括號可以省略
        Consumer<String> con1 = (s) -> {
            System.out.println(s);
        };
        con1.accept("今天是個好日子");

        System.out.println("***************************");

        Consumer<String> con2 = s -> {
            System.out.println(s);
        };
        con2.accept("今天是個好日子");
    }
    @Test
    public void test5(){
        //語法格式五:Lambda需要兩個或以上的參數,多條執(zhí)行語句,并且可以有返回值
        Comparator<Integer> com1 = new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                System.out.println(o1);
                System.out.println(o2);
                return o1.compareTo(o2);
            }
        };

        System.out.println("*******************");

        Comparator<Integer> com2 = (o1,o2) -> {
            System.out.println(o1);
            System.out.println(o2);
            return o1.compareTo(o2);
        };
    }
    @Test
    public void test6(){
        //語法格式六:當Lambda體只有一條語句時,return與大括號若有,都可以省略
        Comparator<Integer> com1 = (o1,o2) -> {
            System.out.println(o1);
            System.out.println(o2);
            return o1.compareTo(o2);
        };

        System.out.println("*******************");

        Comparator<Integer> com2 = (o1,o2) -> o1.compareTo(o2);
    }
}

2. 函數式(Functional)接口

  • 只包含一個抽象方法的接口,稱為函數式接口
  • 你可以通過 Lambda 表達式來創(chuàng)建該接口的對象
  • 我們可以在一個接口上使用@FunctionalInterface注解,這樣做可以檢查它是否是一個函數式接口
  • 以前用匿名實現類表示的現在都可以用Lambda表達式來寫
  • 在java.util.function包下定義了Java 8 的豐富的函數式接口

3. 方法引用與構造器引用

3.1 方法引用

  1. 使用情景:當要傳遞給Lambda體的操作,已經有實現的方法了,可以使用方法引用

  2. 方法引用本質:其本質為Lambda表達式,而Lambda表達式是為函數式接口的實例,所以方法引用,也是函數式接口的實例

  3. 使用格式:類(對象) :: 方法名

  4. 具體使用情況

    • 對象 :: 非靜態(tài)方法(實例方法)
  • 類 :: 靜態(tài)方法
  • 類 :: 非靜態(tài)方法
  1. 使用要求:要求接口中抽象方法的形參列表和返回值類型,與方法引用的方法的形參列表和返回值類型相同,但當類調用非靜態(tài)方法時,可以不相同

3.2 構造器引用與數組引用

構造器引用

和方法引用類似,函數式接口的抽象方法的形參列表和構造器的形參列表一致。抽象方法的返回值類型即為構造器所屬類的類型

數組引用

可以把數組看做是一個特殊的類,則寫法與構造器引用一致

4. 強大的Stream API

4.1 Stream API概述

什么是Stream API

  • Stream API ( java.util.stream) 把真正的函數式編程風格引入到Java中
  • Stream 是 Java8 中處理集合的關鍵抽象概念,它可以指定你希望對集合進行的操作,可以執(zhí)行非常復雜的查找、過濾和映射數據等操作
  • 使用Stream API 對集合數據進行操作,就類似于使用 SQL 執(zhí)行的數據庫查詢
  • Stream 和 Collection 集合的區(qū)別:Collection 是一種靜態(tài)的內存數據結構,而 Stream 是有關計算的。前者是主要面向內存,存儲在內存中,后者主要是面向 CPU,通過 CPU 實現計算
  • 集合講的是數據,Stream講的是計算

Stream的操作步驟

  1. 創(chuàng)建Stream:一個數據源(如:集合、數組),獲取一個流
  2. 中間操作:一個中間操作鏈,對數據源的數據進行處理
  3. 終止操作(終端操作) :一旦執(zhí)行終止操作,就執(zhí)行中間操作鏈,并產生結果。之后,不會再被使用

注意事項

  • Stream 自己不會存儲元素
  • Stream 不會改變源對象。相反,他們會返回一個持有結果的新Stream
  • Stream 操作是延遲執(zhí)行的。這意味著他們會等到需要結果的時候才執(zhí)行

4.2 Stream的實例化

Stream的實例化有四種方式

  1. 創(chuàng)建Stream方式一:通過集合
  2. 創(chuàng)建Stream方式二:通過數組
  3. 創(chuàng)建Stream方式三:通過Stream的of()
  4. 創(chuàng)建Stream方式四:創(chuàng)建無限流(不常使用)
//導入的包有:import org.junit.Test;import java.util.Arrays;import java.util.List;import java.util.stream.IntStream;import java.util.stream.Stream;

public class StreamTest {
    //創(chuàng)建Stream方式一:通過集合
    @Test
    public void test1(){
        //先創(chuàng)建一個集合
        List<Employee> employees = EmployeeData.getEmployees();

        //default Stream<E> stream() : 返回一個順序流
        Stream<Employee> stream = employees.stream();

        //default Stream<E> parallelStream() : 返回一個并行流
        Stream<Employee> parallelStream = employees.parallelStream();
    }

    //創(chuàng)建Stream方式二:通過數組
    @Test
    public void test2(){
        int[] arr = new int[]{1,2,3,4,5,6};
        //調用Array類的static <T> Stream<T> stream(T[] array): 返回一個流
        IntStream stream = Arrays.stream(arr);

        Employee e1 = new Employee(1001,"Tom");
        Employee e2 = new Employee(1002,"Jerry");
        Employee[] arr1 = new Employee[]{e1,e2};
        //常見的數組可以,自定義的數組arr1也行
        Stream<Employee> stream1 = Arrays.stream(arr1);
    }

    //創(chuàng)建Stream方式三:通過Stream的of()
    @Test
    public void test3(){
        Stream<Integer> stream = Stream.of(1,2,3,4,5,6);
    }
}

4.3 Stream的中間操作

  1. 篩選與切片
//篩選與切片
    @Test
    public void test1(){
        List<Employee> list = EmployeeData.getEmployees();
        //filter(Predicate p):接收Lambda,從流中排除某些元素
        Stream<Employee> stream = list.stream();
        //查詢員工表中薪資大于7000的員工信息
        stream.filter(e -> e.getSalary() > 7000).forEach(System.out::println);

        //limit(n):截斷流,使其元素不超過給定數量
        list.stream().limit(3).forEach(System.out::println);

        //skip(n):跳過元素,返回一個扔掉了前n個元素的流,若流中元素不足n個,則返回一個空流
        list.stream().skip(3).forEach(System.out::println);

        //distinct():篩選,通過流所生成元素的hashCode()和equals()去除重復元素
        list.stream().distinct().forEach(System.out::println);
    }
  1. 映射
//映射
    @Test
    public void test2(){
        //接收一個函數作為參數,該函數會被應用到每個元素上,并將其映射成一個新的元素
        List<String> list = Arrays.asList("aa","bb","cc","dd");
        list.stream().map(str -> str.toUpperCase()).forEach(System.out::println);
    }
  1. 排序
//排序
    @Test
    public void test3(){
        //sorted():自然排序
        List<Integer> list = Arrays.asList(12,45,-8,2,56,34);
        list.stream().sorted().forEach(System.out::println);
        //使用自然排序的條件是:所指定泛型要實現Comparable接口

        //sorted(Comparator com):定制排序
        List<Employee> employees = EmployeeData.getEmployees();
        employees.stream().sorted((e1,e2) -> Integer.compare(e1.getAge(),e2.getAge()))
                .forEach(System.out::println);
    }

4.4 Stream的終止操作

  1. 匹配與查找
//匹配與查找
    @Test
    public void test1(){
        List<Employee> employees = EmployeeData.getEmployees();
        //allMatch(Predicate p):檢查是否匹配所有元素:所有員工年齡是否大于18
        boolean allMatch = employees.stream().allMatch(e -> e.getAge() > 18);
        System.out.println(allMatch);

        //anyMatch(Predicate p):檢查是否至少匹配一個元素:是否存在員工工資大于1000
        boolean anyMatch = employees.stream().anyMatch(e -> e.getSalary() > 1000);
        System.out.println(anyMatch);

        //noneMatch(Predicate p):檢查是否沒有匹配所有元素:是否存在員工姓“雷”
        boolean noneMatch = employees.stream().noneMatch(e -> e.getName().startsWith("雷"));
        System.out.println(noneMatch);

        //findFirst():返回第一個元素
        Optional<Employee> employee = employees.stream().findFirst();
        System.out.println(employee);

        //findAny():返回當前流中的任意元素
        Optional<Employee> employee1 = employees.stream().findAny();
        System.out.println(employee1);

        //count():返回流中元素總個數
        long count = employees.stream().count();
        System.out.println(count);

        //max(Comparator c):返回流中最大值:返回最高的工資
        Optional<Double> maxSalary = employees.stream().map(e -> e.getSalary()).max(Double::compare);
        System.out.println(maxSalary);

        //min(Comparator c):返回流中最小值:返回最低的工資
        Optional<Employee> minSalary = employees.stream().min((e1, e2) -> Double.compare(e1.getSalary(), e2.getSalary()));
        System.out.println(minSalary);

        //forEach(Consumer c):內部迭代
        // 使用 Collection 接口需要用戶去做迭代,稱為外部迭代
        // 相反,Stream API 使用內部迭代——它幫你把迭代做了
        employees.stream().forEach(System.out::println);
    }
  1. 歸約
//規(guī)約
    @Test
    public void test2(){
        //reduce(T iden, BinaryOperator b) 可以將流中元素反復結合起來,得到一個值。返回 T
        //練習:計算1-10的自然數的和
        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        Integer sum = list.stream().reduce(0, Integer::sum);
        System.out.println(sum);

        //reduce(BinaryOperator b) 可以將流中元素反復結合起來,得到一個值。返回 Optional<T>
        //練習:計算公司所有員工工資的總和
        List<Employee> employees = EmployeeData.getEmployees();
        Stream<Double> salaryStream = employees.stream().map(Employee::getSalary);
        Optional<Double> sumMoney = salaryStream.reduce((d1, d2) -> d1 + d2);
        System.out.println(sumMoney);
    }
  1. 收集
//收集
    @Test
 public void test3(){
        //collect(Collector c)將流轉換為其他形式。接收一個 Collector接口的實現,用于給Stream中元素做匯總的方法
        //練習:查找工資大于6000的員工,結果返回為一個List或Set

        //結果返回為一個List
        List<Employee> employees = EmployeeData.getEmployees();
        List<Employee> list = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toList());
        list.forEach(System.out::println);

        //結果返回為一個Set
        Set<Employee> set = employees.stream().filter(e -> e.getSalary() > 6000).collect(Collectors.toSet());
        list.forEach(System.out::println);
    }

5. Optional類

Optional< T > 類(java.util.Optional) 是一個容器類,它可以保存類型T的值,代表這個值存在。或者僅僅保存null,表示這個值不存在。

原來用 null 表示一個值不存在,現在 Optional 可以更好的表達這個概念。并且可以避免空指針異常

Optional提供很多有用的方法,這樣我們就不用顯式進行空值檢測

  1. 創(chuàng)建Optional類對象的方法
    • Optional.of(T t):創(chuàng)建一個 Optional 實例,t必須非空
    • Optional.empty():創(chuàng)建一個空的 Optional 實例
    • Optional.ofNullable(T t):t可以為null
  2. 判斷Optional容器中是否包含對象
    • boolean isPresent():判斷是否包含對象
  3. 獲取Optional容器的對象
    • T get(): 如果調用對象包含值,返回該值,否則拋異常
    • T orElse(T other) 如果有值則將其返回,否則返回指定的other對象

舉例說明Optional類

?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容