再來看看Java的新特性——其餘新特性

關於剩餘Java8新特性知識點總結,包含:默認方法、Optional、CompletableFuture、時間相關。java

默認方法

默認方法皆在幫助Java新功能能夠兼容低版本JDK已開發的程序。 好比說,給一個低版本已存在的接口增長新方法,那原來實現該接口的類是否是都須要實現新的方法,這很是不友好,也不利於項目JDK版本的升級,因此引入新的規則默認方法。json

使用方法也很是簡單,只須要在接口方法前加上關鍵字default,而後再將其實現之就行了。bash

public interface Parent {
    default void hello(){
        System.out.println("hello");
    }
}
public class Son implements Parent {
    public static void main(String[] args) {
        Son son = new Son();
        son.hello();
    }
}
複製代碼

默認方法很好的解決了菱形繼承的問題,雖然Java是單繼承,通常狀況下不會出現這種問題,可是別忘了Java除了繼承,還有實現,假設有一下這種狀況。工具

Son實現了Parent、Parent1,Parent和Parent1都繼承了GrandParent,而GrandParent中有一個抽象方法hello,而後Son就會報錯。而若是將GrandParent中的方法改爲默認方法,這個爲你就解決了。post

//這種方式,Son會報錯
public interface GrandParent {
     void hello();
}
//這種方式就ok了
public interface GrandParent {
    default void hello(){
        System.out.println("hello");
    }
}
複製代碼

其實有了默認方法,一個Java類能夠實現N多個接口,不管它們多麼錯綜複雜。可是爲了代碼層次,最好使用代理模式,提早實現一層代理類封裝好全部的接口,真正繼承的類再去繼承代理類,這樣使用起來就會很舒服了。性能

Optional

但凡寫過Java的同窗,必定知道null的存在,null是那些從未定義對象的指向。爲了不NullPointerException的出現,代碼中要加大量的if判斷。爲了讓這種冗餘的無心義的代碼消失,爲了更加符合Java設計哲學,Optional應運而生。ui

Optional就是將用戶建立的對象再進一步封裝,使用戶對象只是Optional對象的一部分,這樣對於開發人員層面來講,就不會直接操做未定義的對象了。spa

建立Optional

假設咱們的用戶類就是上一節中的Son。建立一個包含Son對象的Optional,而且Son對象目前指向爲null。使用靜態方法Optional.empty()設計

Optional<Son> optCar = Optional.empty(); 
複製代碼

接着將存在的用戶對象Son放到Optional中。代理

Son son = new Son();
Optional<Son> sonOptional = Optional.of(son);
複製代碼

不過使用Optional.of須要保證參數必須不爲null,不然就會拋出NullPointerException異常,爲了解決這個問題,可使用下面這個方法。

Optional<Son> sonOptional = Optional.ofNullable(son); 
複製代碼

Optional結合流操做

不只僅是判空問題,Optional能夠自然的和Stream結合。爲了方便,咱們給Son類增長屬性name、age。

@Data
public class Son implements Parent,Parent2 {
    private String name;
    private Integer age;
}
複製代碼

如今假設咱們須要知道son的name,首先須要判斷son是否爲空,再使用方法son.getName()對吧。然而有了Optional咱們可使用map這麼寫。

//原始寫法
Son son = null;
if(Objects.nonNull()){
    String name = son.getName();
}
//新寫法
Son son = null;
Optional<Son> sonOptional = Optional.of(son);
Optional<String> name = sonOptional.map(Son::getName);
複製代碼

值得一提的是經過Stream操做轉化來的對象仍是Optional,只不過泛型變成了預期值類型。

Optional嵌套問題

若是看過我上篇寫的Stream的博客,那麼除了map,你必定還記得flatMap, flatMap 能夠合併Stream,一樣的 flatMap 能夠將多個嵌套的Optional進行合併。下面舉個例子說明一下,爲了說明問題新建兩個類Computer、CPU,顯而易見CPU是Computer的一部分。咱們須要知道某品牌電腦CPU的生產廠家。

@Data
public class CPU {
    private String name;
    private String manufacturers;
}
@Data
public class Computer {
    private String name;
    private Optional<CPU> cpu;
}
複製代碼

首先使用map看一下效果。

Optional<Computer> optionalComputer = Optional.of(computer);
Optional<String> stringOptional = optionalComputer
    .map(Computer::getCpu)
    .map(CPU::getManufacturers);//別說運行了,這行編譯失敗
System.out.println(stringOptional.get());
複製代碼

第4行編譯失敗,那是由於經歷第3行,此時對象的結構爲Optional<Optional<CPU>>,此時的泛型是Optional<CPU>,沒法直接調用CPU::getManufacturers

因此就須要使用flatMap將兩層Optional合併。

Optional<Computer> optionalComputer = Optional.of(computer);
Optional<String> stringOptional = optionalComputer
    .flatMap(Computer::getCpu)
    .map(CPU::getManufacturers);
複製代碼

ok,完美執行了。固然了,Stream中有不少方法這裏都適用,好比filter。

Optional數據讀取

最直接的方法就是get(),可是get()方法須要提早判空,若是用戶對象(就是泛型類的對象)爲null,get()方法就會報錯。

stringOptional.get()
複製代碼

固然,你要執意使用get()方法,Java也提供了更友好的方法orElse(),這個方法能夠當對象是空的時候,給一個默認值。

stringOptional.orElse("juejin")
複製代碼

對於orElse(),還有一個升級版本的方法orElseGet(),是orElse()延時版本,當只有使用默認值的時候,纔會運算orElseGet()的參數,這樣就避免了默認值是耗時操做影響性能。

stringOptional.orElseGet(()->"juejin")
複製代碼

若是你想在對象不存在的時候,拋出一個異常,就可使用方法orElseThrow()

stringOptional.orElseThrow(Exception::new)
複製代碼

還有一個很是好用的方法ifPresent(),這個方法能夠判斷對象是否存在。

if (stringOptional.isPresent()){
	System.out.println("stringOptional.isPresent()");
}
複製代碼

CompletableFuture

寫過一篇《強大的CompletableFuture》

新的日期API

雖然說如今有不少成型的第三方工具包,例如Hutool。處理時間問題多了不少選擇,可是JDK自己的方法,不只提供了某種意義上的最佳實踐,還讓代碼侵入性幾乎爲零。

LocalDate 和 LocalTime

相信不少使用過Java8的小夥伴都用過LocalDateTime,沒錯,就是LocalDate和LocalTime 的結合形式,分別控制着年月日、時分秒。

LocalDate localDate = LocalDate.of(2019,11,24);
localDate.getYear();
localDate.getMonth();
localDate.getDayOfYear();
LocalTime localTime = LocalTime.of(18,40,03);
localTime.getHour();
localTime.getMinute();
localTime.getSecond();
複製代碼

這兩個方法比較簡單,能夠靈活的對年月日時分秒進行讀取和操做。然而真正使用多的是他們的結合版本LocalDateTime

Instant

這個類能夠獲取機器時間,就是從1970年開始計算的時間,舉例獲取時間戳。

Instant instant = Instant.now();
System.out.println(instant.getEpochSecond());
複製代碼

固然getEpochSecond()這個方法還能夠傳參數,相對於當前時間位移必定的時間間隔。

Duration 或 Period

Duration能夠獲取兩個時間之間的間隔。

Duration d1 = Duration.between(time1, time2);
Duration d1 = Duration.between(dateTime1, dateTime2);
Duration d2 = Duration.between(instant1, instant2);
複製代碼

其中參數能夠是 LocalTimes 、 LocalDateTimes 、 Instant。以上能夠計算秒和納秒之間的大小。

若是須要計算年、月、日之間的時間間隔,就須要用Period

Period tenDays = Period.between(LocalDate.of(2014, 3, 8),
 								LocalDate.of(2014, 3, 18)); 
複製代碼

時間操做

就拿LocalDateTimes舉例吧,這個用的最多,新的時間類型能夠快捷的對時間進行修改。

LocalDateTime localDateTime = LocalDateTime.now();
//直接修改時間,不對原始數據操做,生成新的對象。
localDateTime.withHour(1).withMonth(1);
//經過位移修改時間,不對原始數據操做,生成新的對象。
localDateTime.plusDays(12);
localDateTime.plusMinutes(33);
複製代碼

TemporalAdjuster

除了顯示的修改時間,還能夠用JDK提供的一些提早定義好的方法。

import static java.time.temporal.TemporalAdjusters.*;//注意須要這麼導入
LocalDate date1 = LocalDate.of(2019, 11, 24);
System.out.println(date1);//2019-11-24
LocalDate date2 = date1.with(nextOrSame(DayOfWeek.SUNDAY));
System.out.println(date2);//2019-11-24
LocalDate date3 = date2.with(lastDayOfMonth());
System.out.println(date3);//2019-11-30
複製代碼

更多操做見下表

DateTimeFormatter

這個沒必要多說,將事件類型轉化成String類型時,須要的樣式格式。

LocalDateTime localDateTime = LocalDateTime.now();
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:SS", 									Locale.CHINA);
System.out.println(localDateTime.format(dateTimeFormatter));
//2019-11-24 19:41:77
複製代碼

ZoneId

處理不一樣的時區,ZoneId 類替代了原來的 TimeZone 類。

LocalDateTime localDateTime = LocalDateTime.now();
ZoneId romeZone = ZoneId.of("Europe/Rome");
ZoneId shangHaiZone = ZoneId.of("Asia/Shanghai");
System.out.println(localDateTime.atZone(romeZone));
System.out.println(localDateTime.atZone(shangHaiZone));
//2019-11-24T19:52:13.105+01:00[Europe/Rome]
//2019-11-24T19:52:13.105+08:00[Asia/Shanghai]
複製代碼

惟一不爽的是ZoneId.of()參數是字符串(大洲/城市),沒有枚舉類,須要開發人員手動輸入。

個人公衆號

個人公衆號用於博客同步。

相關文章
相關標籤/搜索