jdk8

weixin_33728268發表於2017-05-30

Java 8是Java自Java 5(釋出於2004年)之後的最重要的版本。這個版本包含語言、編譯器、庫、工具和JVM等方面的十多個新特性。

Lambda表示式和函式式介面

['læmdə] 朗姆蹬..
jdk8之前,各種的匿名內部類,大把大把拖沓的程式碼,程式毫無美感可言!既然java中一切皆為物件,那麼,就類似於某些動態語言一樣,函式也可以當成是物件,程式碼塊也可以當成是物件啊,隨著函數語言程式設計的概念越來越深入人心,java中CODE=OBJECT的這一天終於到來了!
ambda的語法 包含3個部分:
(1)括弧包起來的引數 ,引數可以寫型別,也可以不寫
(2)一個箭頭
(3)方法體,可以是單個語句,也可以是語句塊 , 方法可以有返回,也可以無返回,如果有多個語句,還要返回值,需要加上return

lambda的定義:
lambda是方法的實現
lambda是延遲執行的
首先看一個用Runable的實現:

public static void main(String args[]){
         Runnable r = ()->System.out.println("hello,lambda");
         r.run();
}

為了配合lambda,jdk8引入了一個新的定義叫做:函式式介面(Functional interfaces)。

函式式介面

函式式介面的定義:
是一個介面
只有一個待實現的方法
jdk8開始,介面可以有default方法,所以,函式式介面也是可以有default方法的,但是,只能有一個未實現的方法。 與此對應,新引入了一個註解: @FunctionalInterface
這個註解只是起文件的作用,說明這個介面是函式式介面,編譯器並不會使用這個註解來決定一個介面是不是函式式介面。
不管加不加@FunctionalInterface這個註解,下面的介面都是函式式介面:

interface Something { 
  public String doit(Integer i); //只有一個未實現的方法
} 

函式式介面如何與lambda結合使用的呢?,只含有一個介面方法的函式式介面可以隱式轉換為Lambda表示式。java.lang.Runnable和java.util.concurrent.Callable是函式式介面的最佳例子。在實踐中,函式式介面非常脆弱:只要某個開發者在該介面中新增一個函式,則該介面就不再是函式式介面進而導致編譯失敗。為了克服這種程式碼層面的脆弱性,並顯式說明某個介面是函式式介面,Java 8 提供了一個特殊的註解@FunctionalInterface(Java 庫中的所有相關介面都已經帶有這個註解了),舉個簡單的函式式介面的定義:

@FunctionalInterfacepublic interface Functional { 
         void method();
}

不過有一點需要注意,[預設方法和靜態方法]是不會破壞函式式介面的定義,因此如下的程式碼是合法的。

@FunctionalInterfacepublic interface FunctionalDefaultMethods { 
       void method(); 
       default void defaultMethod() {
       } 
}

列如:

public  void test2(){
      HaveArgs notArgs = (String x,Integer xx)->{
            System.out.println(x);
            System.out.println(xx);
      };
      notArgs.doSomething("good",32);
}

預設方法

類似抽象類裡的公用方法

為什麼不能用預設方法來過載equals,hashCode和toString?
介面不能提供對Object類的任何方法的預設實現。這意味著從介面裡不能提供對equals,hashCode或toString的預設實現。
這剛看起來挺奇怪的,但考慮到一些介面實際上是在文件裡定義他們的equals行為的。List介面就是一個例子了。因此,為什麼不允許這樣呢?
Brian Goetz在這個問題上的冗長的回覆裡給出了4個原因。我這裡只說其中一個,因為那個已經足夠說服我了:
它會變得更困難來推導什麼時候該呼叫預設的方法。如果一個類實現了一個方法,那總是優先於預設的實現的。所有介面例項都對equals/hashCode/toString的非預設實現,一個在介面上這些的預設版本都是沒用的,它也不會被編譯。

Optional

Java應用中最常見的bug就是[空值異常]在Java 8之前,[Google Guava]引入了Optionals類來解決NullPointerException,從而避免原始碼被各種null檢查汙染,以便開發者寫出更加整潔的程式碼。Java 8也將Optional加入了官方庫。
Optional僅僅是一個容易:存放T型別的值或者null。它提供了一些有用的介面來避免顯式的null檢查。

Optional< String > fullName = Optional.ofNullable( null );
System.out.println( "Full Name is set? " + fullName.isPresent() );        
System.out.println( "Full Name: " + fullName.orElseGet( () -> "[none]" ) ); 
System.out.println( fullName.map( s -> "Hey " + s + "!" ).orElse( "Hey Stranger!" ) );

如果Optional例項持有一個非空值,則isPresent()方法返回true,否則返回false;orElseGet()方法,Optional例項持有null,則可以接受一個lambda表示式生成的預設值;map()方法可以將現有的Opetional例項的值轉換成新的值;orElse()方法與orElseGet()方法類似,但是在持有null的時候返回傳入的預設值。

Streams

Stream 的建立需要指定一個資料來源,比如 java.util.Collection的子類,List或者Set, Map不支援。Stream的操作可以序列執行或者並行執行。
過濾age>12的元素,並輸出:

listperson.stream()
      .filter((it) -> it.getAge() >= 21)
      .forEach((it) -> 
        System.out.println("Have a beer, " + it.getFirstName()));

Date/Time

Java 8中新的時間和日期管理API深受Joda-Time影響,並吸收了很多Joda-Time的精華。新的java.time包包含了所有關於日期、時間、時區、Instant(跟日期類似但是精確到納秒)、duration(持續時間)和時鐘操作的類。新設計的API認真考慮了這些類的不變性(從java.util.Calendar吸取的教訓),如果某個例項需要修改,則返回一個新的物件。

Clock 時鐘
Clock類提供了訪問當前日期和時間的方法,Clock是時區敏感的,可以用來取代 System.currentTimeMillis() 來獲取當前的微秒數。某一個特定的時間點也可以使用Instant類來表示,Instant類也可以用來建立老的java.util.Date物件。

Clock clock = Clock.systemDefaultZone();
long millis = clock.millis();
Instant instant = clock.instant();
Date legacyDate = Date.from(instant);   // legacy java.util.Date

...

Annotation 註解

在Java 8中支援多重註解

以上特性可以滿足java日常開發了,其他特性個人覺得可以直接引入scala開發包,使用scala.

相關文章