Java 8 新特性

1、Lambda 表達式

一、什麼是 Lambda 表達式?

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

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

    // public void test2();
}

 

 

 

 

 

 

二、基礎語法:

  JDK 8 引入一個箭頭操做符 「->」,或者叫 Lambda 操做符。數組

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

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

 

三、舉例:

  以下例,使用匿名函數 與 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);
}

 

 

 

四、核心函數式接口

  使用 Lambda 表達式前提是爲函數式接口,可是 每次都自定義函數式接口,很繁瑣、蛋疼,因此 Java 8 內置了函數式接口,使用時套用便可。app

【四大核心函數式接口:(其他函數式接口用法相似)】
    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());
    }
}

 

 

 

五、方法引用

  若 Lambda 體中的內容在其餘方法中已經實現,能夠經過 方法引用 去引用相關代碼,從而減小代碼的冗餘。方法引用能夠理解爲 Lambda 的另外一種表現形式。dom

【格式:】
    對象名::實例方法名
    類名::靜態方法名
    類名::實例方法名   
注:
    方法引用 的方法與函數式接口中的方法 返回值類型 以及 參數類型要一致。
    當 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");
    }
}

 

 

 

六、構造器引用

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

【格式:】
    類名::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 "));
    }
}

 

 

 

七、數組引用

  與方法引用相似,此處是對數組引用,是 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);
    }
}

 

2、Stream API

一、什麼是 Stream API?

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

二、Stream 操做步驟

  Step1:建立流。
  Step2:流水線操做(對流進行操做)。
  Step3:終止流。
注:
  第二步是不會當即執行的,等待第三步終止發生時,纔開始執行。
  第二步能夠造成鏈式調用,其每一個操做返回的都是一個流。測試

三、建立流的方式

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

【方式一:】
    經過 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);
    }
}

 

 

 

四、流水線操做(操做流)

  流建立以後,就須要對其進行操做。而多個操做能夠鏈接起來,造成一個流水線。
  每一個操做結束,仍然返回一個 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);
    }
}

 

 

 

五、終止操做

  終止流水線操做。

 

查找與匹配操做:

【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));
    }
}

 

 

 

3、日期

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

一、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());
    }

}

 

 

 

二、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());
    }

}

 

 

 

三、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);
    }

}

 

 

 

四、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);
    }

}

 

 

 

五、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));
    }

}

 

 

 

六、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);
    }

}

 

 

 

4、其他特性

一、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")));
    }
}

 

 

 

二、接口中容許存在默認方法、靜態方法

(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");
    }
}

相關文章
相關標籤/搜索