Java 8 新特性


一、Lambda 表達式

1、什么是 Lambda 表達式?

  Lambda 本質是一個匿名函數,可以理解為一段可以傳遞的代碼,像數據一樣傳輸。
  使用 Lambda 可以簡化代碼、使代碼更緊湊、更靈活。
  使用 Lambda 表達式前提 需要函數式接口支持。
注:
  函數式接口:指的是 接口中只有一個抽象方法的接口。可以使用 @FunctionalInterface 注解去判斷、檢查是否為函數式接口。

@FunctionalInterface
public interface Test {
    public void test();

    // public void test2();
}

 

 

 

 

 

 

2、基礎語法:

  JDK 8 引入一個箭頭操作符 “->”,或者叫 Lambda 操作符。

【格式:】
    (參數列表) -> {Lambda 體};
注:
    參數列表指的是 方法的參數,即需要在 Lambda 體中執行的變量。
    Lambda 體指的是 方法體,定義了需要執行的功能。

【語法:】
    若出現一個參數的情況,可以將()省略。
    若出現一行代碼的情況,可以將{}省略。
    對於多個參數的情況,可以省略參數類型(JVM 類型推斷),但()不能省略。
    若{}中只有一行代碼,且為return語句,則可省略return 和 {}。

 

3、舉例:

  如下例,使用匿名函數 與 Lambda 的比較。
  Lambda 可以省去很多代碼,代碼結構緊湊、簡潔。
  使用 Lambda 與使用 匿名函數類似, Lambda 體中即為 匿名函數重寫的方法的方法體,參數列表為 匿名函數重寫的方法的參數列表,使用時,直接調用方法名即可。

【舉例:】

/**
 * 測試 Lambda 表達式用法
 */
public class TestLambda {
    public static void main(String[] args) {
        String str = "helloworld";
        // 使用 匿名函數 時
        test(str, new TestLambdaFunction() {
            @Override
            public void test(String str) {
                System.out.println(str);
            }
        });

        // 使用 Lambda 表達式,此方法等價於上面匿名函數的寫法
        // 只有一個參數,() 可省略,參數類型可省略(JVM自動進行類型推斷), Lambda 體只有一行代碼,{} 可省略。
        test(str, x -> System.out.println(x));
    }

    public static void test(String str, TestLambdaFunction testLambdaFunction) {
        testLambdaFunction.test(str);
    }
}

@FunctionalInterface
interface TestLambdaFunction {
    void test(String str);
}

 

 

 

4、核心函數式接口

  使用 Lambda 表達式前提是為函數式接口,但是 每次都自定義函數式接口,很繁瑣、蛋疼,所以 Java 8 內置了函數式接口,使用時套用即可。

【四大核心函數式接口:(其余函數式接口用法類似)】
    Consumer<T>          消費型接口,有參數 T,沒有返回值。
        抽象方法: void accept(T t);

    Supplier<T>              供給型接口,沒有參數,有返回值 T。
        抽象方法: T get();  

    Function<T, R>         函數型接口,有參數 T,有返回值 R。
        抽象方法:R apply(T var1);
    
    Predicate<T>             斷言型接口,有參數 T,返回值為 boolean 型。
        抽象方法: boolean test(T var1);


【舉例:】

import java.util.Date;
import java.util.function.Consumer;
import java.util.function.Supplier;

/**
 * 測試 Lambda 表達式用法
 */
public class TestLambda {
    public static void main(String[] args) {
        String str = "helloworld";
        // 測試 Consumer<T> 函數式接口,此處定義 Consumer<T> 函數式接口抽象方法的具體實現
        testConsumer(str, x -> System.out.println(x));

        // 測試 Supplier<T> 函數式接口,此處定義 Supplier<T> 函數式接口抽象方法的具體實現
        testSupplier(() -> new Date());
    }

    public static void testConsumer(String str, Consumer<String> consumer) {
        // 此處為 Consumer<T> 函數式接口抽象方法具體調用
        consumer.accept(str);
    }

    public static void testSupplier(Supplier<Date> supplier) {
        // 此處為 Supplier<T> 函數式接口抽象方法具體調用
        System.out.println(supplier.get());
    }
}

 

 

 

5、方法引用

  若 Lambda 體中的內容在其他方法中已經實現,可以通過 方法引用 去引用相關代碼,從而減少代碼的冗余。方法引用可以理解為 Lambda 的另一種表現形式。

【格式:】
    對象名::實例方法名
    類名::靜態方法名
    類名::實例方法名   
注:
    方法引用 的方法與函數式接口中的方法 返回值類型 以及 參數類型要一致。
    當 Lambda 參數列表中 第一個參數 是實例方法的調用者,第二個參數是 實例方法的參數時,才可以使用 類::實例方法名。 比如:String::equals.
    
【舉例:】

import java.io.PrintStream;
import java.util.function.Consumer;

/**
 * 測試 Lambda 表達式用法
 */
public class TestLambda {
    public static void main(String[] args) {
        Consumer<String> consumer0 = new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        };
        consumer0.accept("匿名函數");

        // 一般 Lambda 表達式寫法
        Consumer<String> consumer1 = x -> System.out.println(x);
        consumer1.accept("hello");

        PrintStream printStream = System.out;

        Consumer<String> consumer2 = x -> printStream.println(x);
        consumer2.accept("hello wrold");

        // 使用 對象名::實例方法名 去改寫 Lambda 表達式,本質與 Lambda 表達式一致
        Consumer<String> consumer3 = printStream::println;
        consumer3.accept("world");
    }
}

 

 

 

6、構造器引用

  與方法引用類似,此處是對構造器的引用,是 Lambda 針對構造器的一種寫法。

【格式:】
    類名::new
注:
    構造器引用 的參數列表 與 函數式接口中方法的參數列表 要一致。
    即通過方法參數去確認調用哪一個構造方法。

【舉例:】

import java.util.function.Function;

/**
 * 測試 Lambda 表達式用法
 */
public class TestLambda {
    public static void main(String[] args) {
        // 普通 Lambda 表達式
        Function<String, String> function = (x) -> new String(x).trim();
        System.out.println(function.apply("       ddd hello "));

        // Lambda 表達式 -- 構造器引用
        Function<String, String> function1 = String::new;
        System.out.println(function1.apply("      hello "));

        // 普通 Lambda 表達式,並創建一個對象實例,等價於 上面的構造器引用
        Function<String, String> function2 = (x) -> new String(x);
        System.out.println(function2.apply("      hello "));
    }
}

 

 

 

7、數組引用

  與方法引用類似,此處是對數組引用,是 Lambda 針對數組的一種寫法。

【格式:】
    數組類型[]::new

【舉例:】

import java.util.function.Function;

/**
 * 測試 Lambda 表達式用法
 */
public class TestLambda {
    public static void main(String[] args) {
        // 一般 Lambda 創建一個數組的寫法
        Function<Integer, String[]> function = x -> new String[x];
        System.out.println(function.apply(10).length);

        // 使用數組引用創建一個 數組的寫法
        Function<Integer, String[]> function1 = String[]::new;
        System.out.println(function1.apply(20).length);
    }
}

 

二、Stream API

1、什么是 Stream API?

  Stream API 是 JDK 8 中處理集合的抽象概念,可以對指定的集合進行復雜的操作,比如查找、過濾、映射數據等。
  簡單地理解:Stream API 提供了一種高效且易於使用的處理數據的方式。Stream 就是一個數據通道,一個數據 經過 該通道(一系列流水線操作)后得到一個新的數據。
  Stream 不會存儲數據、不會改變源對象(會創建一個新 Stream)、延遲操作。

2、Stream 操作步驟

  Step1:創建流。
  Step2:流水線操作(對流進行操作)。
  Step3:終止流。
注:
  第二步是不會立即執行的,等待第三步終止發生時,才開始執行。
  第二步可以形成鏈式調用,其每個操作返回的都是一個流。

3、創建流的方式

  要使用流,就得先創建一個流。

【方式一:】
    通過 Collection 集合的 stream() 或者 parallelStream() 方法去創建集合流。
    default Stream<E> stream()             // 創建一個串行流(順序流)
    default Stream<E> parallelStream()     // 創建一個並行流

比如:(對 List 集合創建一個集合流)
    List<String> list = new ArrayList<>();
    Stream<String> stream = list.stream();
    
【方式二:】
    通過 Arrays 工具類的 stream() 方法去創建數組流。
    public static <T> Stream<T> stream(T[] var0)

比如:(對 String 數組創建一個數組流)
    String[] strings = new String[10];
    Stream<String> stream = Arrays.stream(strings);
    
【方式三:】
    通過 Stream 類中的靜態方法 of() 去創建。
    static <T> Stream<T> of(T var0)

比如:(創建一個數組流)
    String[] strings = new String[10];
    Stream<String> stream = Stream.of(strings);
    
【方式四:】
    通過 Stream 類中的靜態方法 iterate() 迭代創建無限流。
    static <T> Stream<T> iterate(final T var0, final UnaryOperator<T> var1)

比如:(創建一個無限流,不斷加 2)
    Stream<Integer> stream = Stream.iterate(0, x -> x + 2);
    
【方式五:】
    通過 Stream 類中的靜態方法 generate() 生成創建無限流。
    static <T> Stream<T> generate(Supplier<T> var0)

比如:(創建一個無限流,隨機生成 0 - 9 內的數)
    Stream<Integer> stream = Stream.generate(() -> (int)(Math.random() * 10));
    
【舉例:】

import java.util.Arrays;
import java.util.List;

public class TestStream {
    public static void main(String[] args) {
        // 創建一個集合流,Arrays.stream() 是創建流操作, forEach 是終止操作
        String[] strings = new String[]{"aa", "bbb", "ccccc", "aa", "ddd"};
        Arrays.stream(strings).forEach(System.out::println);

        // 創建一個集合流,list.stream() 是創建流操作
        List<String> list = Arrays.asList(strings);
        list.stream().forEach(System.out::println);
    }
}

 

 

 

4、流水線操作(操作流)

  流創建之后,就需要對其進行操作。而多個操作可以連接起來,形成一個流水線。
  每個操作結束,仍然返回一個 Stream 流對象,所以可以鏈式調用。
注:
  除非流水線上觸發了終止操作,否則流水線上不做任何處理,只有終止操作觸發后,才開始流水線處理,即惰性求值。

 

篩選與切片操作:

【filter:】
    通過 Stream 類中 filter() 方法進行過濾操作。根據 Lambda 表達式過濾掉部分數據。
    Stream<T> filter(Predicate<? super T> var1);
    
比如:(對流處理,過濾出元素長度大於等於 3 的元素)
    String[] strings = new String[]{"aa", "bbb", "ccccc", "aa", "ddd"};
    Arrays.stream(strings).filter(x -> x.length() >= 3 );
    
【limit:】
    通過 Stream 類中 limit(n) 方法進行截取 n 個元素。
    Stream<T> limit(long var1);
    
比如:(對流處理,截取 2 個元素)
    String[] strings = new String[]{"aa", "bbb", "ccccc", "aa", "ddd"};
    Arrays.stream(strings).limit(2);
    
【skip:】
    通過 Stream 類中 skip(n) 方法進行跳過 n 個元素。
    Stream<T> skip(long var1);
    
比如:(對流處理,跳過 2 個元素,與 limit 互補)
    String[] strings = new String[]{"aa", "bbb", "ccccc", "aa", "ddd"};
    Arrays.stream(strings).skip(2);
    
【distinct:】
    通過 Stream 類中 distinct() 方法進行元素去重。
    Stream<T> distinct();
注:
    根據元素的 hashcode() 以及 equals() 進行判斷,自定義類型需要進行 重寫兩個方法,否則可能不生效。
    
比如:(對流處理,對元素進行去重)
    String[] strings = new String[]{"aa", "bbb", "ccccc", "aa", "ddd"};
    Arrays.stream(strings).distinct();
    
【舉例:】
   
import java.util.Arrays;

public class TestStream {
    public static void main(String[] args) {
        // 創建一個集合流,Arrays.stream() 是創建流操作, forEach 是終止操作。
        // filter()、distinct()、limit(n)、skip(n) 都是中間操作,可以鏈式調用
        String[] strings = new String[]{"aa", "bbb", "ccccc", "aa", "ddd"};
        System.out.println("==========過濾出元素長度大於 3 的元素==========");
        Arrays.stream(strings).filter(x -> x.length() > 3).forEach(System.out::println);

        System.out.println("==========對元素進行去重,需要根據 hashcode、 equals 判斷===========");
        Arrays.stream(strings).distinct().forEach(System.out::println);

        System.out.println("==========截取前兩個元素==============");
        Arrays.stream(strings).limit(2).forEach(System.out::println);

        System.out.println("==========跳過前兩個元素==============");
        Arrays.stream(strings).skip(2).forEach(System.out::println);
    }
}

 

 

 

映射操作:

【map:】
    Stream 類中 map 方法接收一個 Lambda 表達式,並將其應用到每個元素上。
    <R> Stream<R> map(Function<? super T, ? extends R> var1);
    
比如:(分別對每個元素進行處理,將元素轉為大寫)
    String[] strings = new String[]{"aa", "bbb", "ccccc", "aa", "ddd"};
    Arrays.stream(strings).map(x -> x.toUpperCase());

【flatMap:】
    Stream 類中 flatMap 方法接受一個 Lambda 表達式,將其應用在每個元素上(每個元素都為流),最后將所有元素(流)組成一個流返回。
    <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> var1);
    
比如:(將流中每個元素轉為 字符,並將其轉為流,最后再將流合並成一個大流)
    String[] strings = new String[]{"aa", "bbb", "ccccc", "aa", "ddd"};
    Arrays.stream(strings).flatMap(str -> {
        List<Character> list = new ArrayList<>();
        for(Character character : str.toCharArray()) {
            list.add(character);
        }
        return list.stream();
    });
    
【舉例:】

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class TestStream {
    public static void main(String[] args) {
        // 創建一個集合流,Arrays.stream() 是創建流操作, forEach 是終止操作。
        // map()、flatMap() 都是中間操作,可以鏈式調用
        String[] strings = new String[]{"aa", "bbb", "ccccc", "aa", "ddd"};
        System.out.println("==========map 接收一個函數,並應用在每個元素上=============");
        Arrays.stream(strings).map(x -> x.toUpperCase()).forEach(System.out::println);

        System.out.println("==========flatMap 與 map 類似,但是其每處理一個元素都會讓其轉為 Stream 流,最后合並成一個 Stream ==========");
        Arrays.stream(strings).flatMap(x -> {
            List<String> list = new ArrayList<>();
            list.add(x.toUpperCase());
            return list.stream();
        }).forEach(System.out::println);
    }
}

 

 

 

排序操作:

【sorted:(自然排序)】
    Stream 類中的 sorted 方法可以使用自然排序(實現 Comparable 接口)。
    Stream<T> sorted();
    
比如:(對數組進行自然排序)
    String[] strings = new String[]{"aa", "bbb", "ccccc", "aa", "ddd"};
    Arrays.stream(strings).sorted();
        
【sorted:(自定義排序)】
    使用 Comparator 接口自定義排序規則。
    Stream<T> sorted(Comparator<? super T> var1);
    
比如:(根據元素長度進行排序)
    String[] strings = new String[]{"aa", "bbb", "ccccc", "aa", "ddd"};
    Arrays.stream(strings).sorted((x, y) -> x.length() - y.length());
    
【舉例:】
    
import java.util.Arrays;

public class TestStream {
    public static void main(String[] args) {
        // 創建一個集合流,Arrays.stream() 是創建流操作, forEach 是終止操作。
        // sorted() 是中間操作,可以鏈式調用
        String[] strings = new String[]{"aa", "bbb", "ccccc", "aa", "ddd"};
        System.out.println("=======自然排序,根據 Comparable 接口的 compareTo() 方法進行排序=======");
        Arrays.stream(strings).sorted().forEach(System.out::println);

        // 自定義排序,按元素長度降序排序
        System.out.println("=======自定義排序,根據 Comparator 接口的 compare() 方法進行排序=======");
        Arrays.stream(strings).sorted((x, y) -> y.length() - x.length()).forEach(System.out::println);
    }
}

 

 

 

5、終止操作

  終止流水線操作。

 

查找與匹配操作:

【allMatch:】
    檢查是否匹配所有元素,全部匹配則返回 trueboolean allMatch(Predicate<? super T> predicate);

【anyMatch:】
    檢查是否匹配至少一個元素,全不匹配則返回 falseboolean anyMatch(Predicate<? super T> predicate);
    
【noneMatch:】
    檢查所有元素是否均不匹配,均不匹配則返回 trueboolean noneMatch(Predicate<? super T> predicate);

【findFirst:】
    返回第一個元素。
    Optional<T> findFirst();
    
【findAny:】
    返回任意一個元素。
    Optional<T> findAny();

【count:】
    返回流中元素的總個數。
    long count();
    
【max:】
    根據自定義比較規則,找到流中最大值。
    Optional<T> max(Comparator<? super T> comparator);

【min:】
    根據自定義比較規則,找到流中最小值。
    Optional<T> min(Comparator<? super T> comparator);
    
【forEach:】
    遍歷流中每個元素
    void forEach(Consumer<? super T> action);
    
【舉例:】

import java.util.Arrays;

public class TestStream {
    public static void main(String[] args) {
        String[] strings = new String[]{"aa", "bbb", "ccccc", "aa", "ddd"};
        System.out.println("=======判斷流中每個元素長度是否大於 10,全都大於 10,則輸出 true,否則為 false ========");
        System.out.println(Arrays.stream(strings).allMatch(x -> x.length() > 10));

        System.out.println("=======noneMatch 與 allMatch 相反,全都不大於 10,則輸出 true=======");
        System.out.println(Arrays.stream(strings).noneMatch(x -> x.length() > 10));

        System.out.println("=======輸出第一個值===========");
        System.out.println(Arrays.stream(strings).findFirst().get());

        System.out.println("=======輸出當前流中元素大於等於 3 的元素個數=====================");
        System.out.println(Arrays.stream(strings).filter(x -> x.length() >= 3).count());
    }

 

 

 

歸約操作:

【reduce:】
    用於將流中的元素反復結合,並進行處理。
    Optional<T> reduce(BinaryOperator<T> accumulator);
    T reduce(T identity, BinaryOperator<T> accumulator);
    
【舉例:】

import java.util.Arrays;

public class TestStream {
    public static void main(String[] args) {
        String[] strings = new String[]{"aa", "bbb", "ccccc", "aa", "ddd"};
        System.out.println("======反復處理流中的元素,依次拼接元素======");
        System.out.println(Arrays.stream(strings).reduce("", (x, y) -> x + y));

        Integer[] integers = new Integer[]{10, 20, 10, 30};
        System.out.println("======反復處理流中的元素,元素依次相加======");
        System.out.println(Arrays.stream(integers).reduce((x, y) -> {
            System.out.println("====== x ==" + x + "========  y ==" + y + "=======");
            return x + y;
        }).get());
    }
}

 

 

 

收集操作:

【collect:】
    收集流元素,通過 Collector 接口實現,將流元素轉為其他形式。
    <R, A> R collect(Collector<? super T, A, R> collector);
注:
    通過 Collector 接口中的方法決定了如何對流進行收集操作(轉為 set、list 等)。
    Collectors 工具類提供了很多靜態方法,去返回相應的 Collector 類型(可以很方便的收集數據)。

【舉例:】
    
import java.util.*;
import java.util.stream.Collectors;

public class TestStream {
    public static void main(String[] args) {
        String[] strings = new String[]{"aa", "bbb", "ccccc"};
        System.out.println("=====收集流中元素並轉為 List 集合======");
        List<String> list = Arrays.stream(strings).collect(Collectors.toList());
        System.out.println(list);

        System.out.println("=====收集流中元素並轉為 map ========");
//        Map<Integer, String> map = Arrays.stream(strings).collect(Collectors.toMap(x -> x.length(), y -> y));
        Map<Integer, String> map = Arrays.stream(strings).collect(Collectors.toMap(String::length, String::trim));
        map.forEach((x, y) -> System.out.println("=== x == " + x + " === y ==" + y));
    }
}

 

 

 

三、日期

  jdk8 提供了一系列線程安全的日期操作 API,這些 API 實例都是不可變對象(類似於 String)。
注:
  String 不可變性,使用 final 修飾 類名,內部使用 final 修飾一個 char 數組用於保存字符串。
  盡管 final 修飾引用類型,其數據可以修改,但是 String 內部並沒有提供 修改 char 數組的方法,其方法 比如 trim()、replace() 等方法都是返回一個新的 String 對象(修改引用地址,不修改引用具體內容),從而保證對象的不可變性。

1、LocalDate、LocalTime、LocalDateTime(設置、獲取日期)

  這三個 API 用法類似。此處簡單舉個例,方法太多,知曉大概就行。
  LocalDate 用於設置、獲取日期。
  LocalTime 用於設置、獲取時間。
  LocalDateTime 用於設置、獲取日期和時間。

【舉例:】

import java.time.LocalDate;
import java.time.LocalDateTime;

public class Test {
    public static void main(String[] args) {
        // 使用 now 方法可以獲取當前系統時間
        LocalDate localDate = LocalDate.now();
        // 使用 of 方法可以自定義時間
        LocalDateTime localDateTime = LocalDateTime.of(2020, 4, 24, 23, 00, 00);
        System.out.println(localDate);
        System.out.println(localDateTime);

        // 可以使用 plus 相關方法增加日期,使用 minus 相關方法可以減少日期(返回一個新的日期對象)
        localDateTime = localDateTime.plusHours(10);
        localDateTime = localDateTime.minusHours(5);
        System.out.println(localDateTime);

        // 可以使用 get 相關方法獲取相應的年、月、日等
        System.out.println(localDateTime.getYear() + " ===== " + localDateTime.getMonth());
    }

}

 

 

 

2、Instant(設置、獲取時間戳)

  與 LocalDate 等 API 區別為, Instant 可以用來操作時間戳。
  Instant 默認使用 UTC 時區,即與北京時間相差 8 小時。

【舉例:】

import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;

public class Test {
    public static void main(String[] args) {
        // 使用 now 方法可以獲取時間戳,默認為 UTC 時區,即與 北京時間 相差 8 小時
        Instant instant = Instant.now();
        System.out.println(instant);

        // 使用 atOffset 方法可以設置時間偏移量
        OffsetDateTime offsetDateTime = instant.atOffset(ZoneOffset.ofHours(8));
        System.out.println(offsetDateTime);

        // 使用 toEpochMilli 可以獲取時間戳(精確到毫秒)
        System.out.println(instant.toEpochMilli());

        // 使用 getEpochSecond 可以獲取時間戳(精確到秒)
        System.out.println(instant.getEpochSecond());
    }

}

 

 

 

3、Duration、Period(用於計算日期)

  Duration 用於計算 時間 之間的間隔。
  Period 用於計算 日期 之間的間隔。

【舉例:】

import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;

public class Test {
    public static void main(String[] args) {

        LocalDateTime localDateTime = LocalDateTime.now();
        LocalDateTime localDateTime2 = localDateTime.plusHours(5);

        // Duration 用於計算 時間 之間的間隔
        Duration duration = Duration.between(localDateTime, localDateTime2);
        System.out.println(duration);

        LocalDate localDate = LocalDate.now();
        LocalDate localDate2 = localDate.plusDays(3);

        // Period 用於計算 日期 之間的間隔
        Period period = Period.between(localDate, localDate2);
        System.out.println(period);
    }

}

 

 

 

4、TemporalAdjuster(時間矯正器)

  通過 TemporalAdjuster 可以獲取想要的時間。
  一般可以通過 TemporalAdjusters 工具類進行操作。

【舉例:】

import java.time.DayOfWeek;
import java.time.LocalDateTime;
import java.time.temporal.TemporalAdjusters;

public class Test {
    public static void main(String[] args) {
        // 獲取當前系統時間
        LocalDateTime localDateTime = LocalDateTime.now();
        System.out.println(localDateTime);

        // 可以通過 with 相關函數獲取指定的日期,比如獲取當前年中的第二天
        LocalDateTime localDateTime2 = localDateTime.withDayOfYear(2);
        System.out.println(localDateTime2);

        // 可以使用 TemporalAdjusters 工具類進行時間矯正,比如獲取當前系統日期的下一個星期六的日期
        LocalDateTime localDateTime3 = localDateTime.with(TemporalAdjusters.next(DayOfWeek.SATURDAY));
        System.out.println(localDateTime3);
    }

}

 

 

 

5、DateTimeFormatter(日期格式化)

  通過 DateTimeFormatter 可以方便的進行 字符串 與 日期 之間的轉換。
  format 用於 日期 轉 字符串。
  parse 用於 字符串 轉 日期。

【舉例:】

import java.time.DayOfWeek;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class Test {
    public static void main(String[] args) {
        // 獲取當前系統時間
        LocalDateTime localDateTime = LocalDateTime.now();
        System.out.println(localDateTime);

        // 可以使用 DateTimeFormatter 提供的一些日期格式化常量進行格式化
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ISO_DATE;
        System.out.println(dateTimeFormatter.format(localDateTime));

        // 使用 ofPattern 可以指定模板,使用 模板.format(時間) 可以將時間按照模板轉為字符串。
        // 使用 時間.parse(字符串, 模板) 可以將字符串按照模板轉為時間
        DateTimeFormatter dateTimeFormatter2 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
        System.out.println(dateTimeFormatter2.format(localDateTime));
        System.out.println(LocalDateTime.parse(dateTimeFormatter2.format(localDateTime), dateTimeFormatter2));
    }

}

 

 

 

6、ZonedDateTime(獲取帶時區的時間)

【舉例:】

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;

public class Test {
    public static void main(String[] args) {
        // 獲取當前系統時間
        LocalDateTime localDateTime = LocalDateTime.now();
        System.out.println(localDateTime);

        // 獲取所有時區
        // Set<String> set = ZoneId.getAvailableZoneIds();
        // set.forEach(System.out::println);

        // 獲取 Asia/Pontianak 時區的時間
        LocalDateTime localDateTime2 = LocalDateTime.now(ZoneId.of("Asia/Pontianak"));
        System.out.println(localDateTime2);
        ZonedDateTime zonedDateTime = localDateTime2.atZone(ZoneId.of("Asia/Pontianak"));
        System.out.println(zonedDateTime);
    }

}

 

 

 

四、其余特性

1、Optional<T>

(1)什么是 Optional?
  指的是 java.util.Optional,是一個容器類,代表一個值的存在或不存在。
  當一個值可能為 null 時,可以使用 Optional 包裝一下,從而盡量避免空指針異常。

(2)常用方法:

【get:】
    獲取 Optional 的值。
    public T get()
    
【of:】
    創建一個 Optional 實例,參數為 null 時會報 空指針異常。
    public static <T> Optional<T> of(T var0)

【empty:】
    創建一個 Optional 空實例,參數為 null 不會報 空指針異常。
    public static <T> Optional<T> empty()

【ofNullable:】
    創建一個 Optional 實例,參數為 null 則調用 empty(), 不為 null 則調用 of()
    public static <T> Optional<T> ofNullable(T var0)
    
【isPresent:】
    判斷 Optional 實例中是否存在值。
    public boolean isPresent()
    
【orElse:】
    如果 Optional 不為 null,則返回該值,若為 null,則返回 var1.
    public T orElse(T var1)
    
【orElseGet:】
    與 orElse 類似,其可以傳入 Lambda。
    public T orElseGet(Supplier<? extends T> var1)
    
【map:】
    對 Optional 值進行處理,若不存在 Optional 值,則返回 Optional.empty()
    public <U> Optional<U> map(Function<? super T, ? extends U> var1)

【flatMap:】
    與 map 類似,但是處理結果類型必須為 Optional
    public <U> Optional<U> flatMap(Function<? super T, Optional<U>> var1)
    
【舉例:】

import java.util.Optional;

public class Test {
    public static void main(String[] args) {
        Optional<String> optional = Optional.of(new String("hello"));
        if (optional.isPresent()) {
            System.out.println(optional.get());
        }

        optional.orElse(new String("hello world"));
        System.out.println(optional.orElse(new String("hello world")));

        Optional<String> optional2 = Optional.empty();
        System.out.println(optional2.orElse(new String("hello world")));
    }
}

 

 

 

2、接口中允許存在默認方法、靜態方法

(1)簡介
  jdk 8 對接口中可以存在的方法進行了調整。
  jdk 8 之前,接口中只能存在 抽象方法。
  jdk 8,接口中可以存在 實現方法,可以分為 默認方法 和 靜態方法。
其中:
  默認方法使用 default 關鍵字修飾。
  靜態方法使用 static 關鍵字修飾。

(2)沖突
  接口方法多了,沖突就可能隨之而來了。
沖突一:
  一個類繼承了一個父類、實現了一個接口,且父類、接口中存在同名方法,那子類會使用哪個方法嘞?

答案:
  子類會優先使用 父類 中實現的方法。

【舉例:】

public class Test extends A implements B{
    public static void main(String[] args) {
        Test test = new Test();
        test.show();
        test.show2();
    }
}
interface B {
    default void show() {
        System.out.println("Hello Java");
    }
    static void show2() {
        System.out.println("Hello Java NB");
    }
}
class A {
    public void show() {
        System.out.println("Hello JavaScript");
    }
    public static void show2() {
        System.out.println("Hello JavaScript NB");
    }
}

 

 

沖突二:
  一個類實現了兩個接口,且接口中存在同名方法,那子類會使用哪個方法嘞?

答案:
  子類需要重寫某一個接口的方法,自定義方法實現邏輯。

【舉例:】

public class Test implements B,A{
    public static void main(String[] args) {
        Test test = new Test();
        test.show();
    }

    @Override
    public void show() {
        A.super.show();
    }
}
interface B {
    default void show() {
        System.out.println("Hello Java");
    }
}
interface A {
    default void show() {
        System.out.println("Hello JavaScript");
    }
}

 


免責聲明!

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



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