未來已來,Java8 新特性快速入門

未來已來,Java8 新特性快速入門

自2014年3月18日發佈以來,四年的時間裡各大廠商已經逐漸採用Java8重構工程軟件,招聘需求裡也已將其作為Java開發工程師的必備技能。掌握Java8新特性成了軟件開發人員不得不重視的能力。本人結合相關教程及書籍學習了Java8新特性,特此分享。

Lambda表達式(閉包)

Lambda(λ,希臘數字中的第十一個數字,由於λ演算式的存在,它也代表閉包)表達式是JAVA 8中最令人激動的新特性,它使得Java編程中出現了函數式編程的概念,在其他高級語言中如Python(解釋型、動態數據類型、面向對象),常用Lambda表達式創建匿名函數。Lambda表達式允許我們將函數當成一個參數看待,可以將其傳遞給一個方法或者直接將表達式所在代碼塊作為數據處理,這一設計在JAVA 8之前只能採用匿名內部類的方式實現,這損耗了大量的編程時長及讀碼效率。

Example 1 遍歷數組

Java 7

Integer[] arr = new Integer[]{2, 9, -2, 3};for(int i : arr){ System.out.println(i);}

Java 8

Arrays.asList(2, 9, -2, 3).foreach( (Integer e) -> { System.out.println(e); } );

可以看到最簡單的Lambda表達式可以由數值列表,(變量代表名),->以及{行為代碼}組成。但實際上,()包括變量e的類型名都是可以省略的,省略的變量類型名由編譯器自行推理,深知{}也是可以省略的,所以最短代碼應該是:

Arrays.adList(2, 9, -2, 3).foreach( e -> System.out.println(e) );

Lambda表達式可以引用類成員變量或全局變量,但JVM會自動將其隱形轉換成final類型,理由與匿名內部類的參數引用時必須為final一致3。

String separator = ",";Arrays.adList(2, 9, -2, 3).foreach( e -> System.out.print(e) + separator ); // 變量separator將被隱式轉換為final類型。

為了使Java中原有的功能能夠與Lambda表達式結合使用,官方規定函數接口(除下文即將介紹的默認函數及靜態函數外,只有一個函數的接口)能夠隱式轉換成Lambda表達式,java.lang.Runnable和java.concurrent.Callable是函數接口的最佳例子。此外,為了解決函數接口定義與Lambda表達式的衝突,官方提供了一個特殊的註解@FuntionalInterface用以表示函數接口,這意味著你以後定義上述函數接口將採用此註解標識,在Jdk中所有相關的函數也已經加上此註解。如:

@FunctionalInterfacepublic interface Callable { V call() throws Exception;}

接口新增默認方法和靜態方法

眾所周知,接口相關知識點是面試中老生常談的話題。在以往接口被定義為抽象方法的集合,接口中的方法會被隱式指定為public abstract,而變量會被隱式指定為public static final,其他修飾符會導致報錯。而現在,Java中接口的定義將被修改,接口中除public抽象函數外新增了默認方法和靜態方法。

public interface Defaulable { default void hello(){ System.out.println("這是接口的默認方法"); } static void create(){ System.out.println("這是接口的靜態方法"); }} public class DefauleImp implements Defaulable{// @Override// public void hello() {// System.out.println("Hello world");// } public static void main(String[] args) { new DefauleImp().hello(); Defaulable.create(); }}

默認方法可被繼承或重寫,而靜態方法可與類的靜態方法一樣直接通過接口名.方法名調用。

方法引用

方法引用的最大用途是簡寫Lambda表達式。

方法引用Lambda表達式
String::valueOfx -> String.valueOf(x)
Object::toStringx -> x.toString()
x::toString() -> x.toString()
ArrayList::new () -> new ArrayList<>()

拓寬註解的使用範圍

猶記得在舊版的Java教程中沒有註解的出現,當學習Struts等第三方流行框架時出現註解使我極其不適。而現在註解已經成為JAVA世界一種獨特且無可替代的定義方式。JAVA8中,註解幾乎可以用在任何元素之上:類、接口、元素、方法,甚至是異常。

import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;import java.util.ArrayList;import java.util.Collection;public class Annotations {  @Retention( RetentionPolicy.RUNTIME )  @Target( { ElementType.TYPE_USE, ElementType.TYPE_PARAMETER } )  public @interface NonEmpty {  }  public static class Holder< @NonEmpty T > extends @NonEmpty Object { public void method() throws @NonEmpty Exception {  } }  @SuppressWarnings( "unused" ) public static void main(String[] args) { final Holder< String > holder = new @NonEmpty Holder< String >();  @NonEmpty Collection< @NonEmpty String > strings = new ArrayList<>();  }}

運行時獲取參數名稱

在Java8以前,需要在運行時得到參數的名稱是一件比較困難的事情,程序員們雖然提供了諸如Paranamer liberary等方法,但用起來總歸不算順暢,而現在Java8從字節碼層面(使用新的javac編譯器以及-parameters參數)和語言層面(Parameter.getName()和反射API)提供了這一支持。

public static void main(String[] args) {  for (Method m : ${ClassName}.class.getMethods()) { System.out.println("----------------------------------------"); System.out.println(" method: " + m.getName()); System.out.println(" return: " + m.getReturnType().getName()); for (Parameter p : m.getParameters()) { System.out.println("parameter: " + p.getType().getName() + ", " + p.getName()); } }}

但是在JAVA8中這個功能是默認關閉的,如果需要打開需要加上參數-parameters進行編譯,如果你使用maven作為構建工具,也可以直接在編譯插件中加入此參數,如下:

 org.apache.maven.plugins  
maven-compiler-plugin 3.1 -parameters 1.8 1.8

Optional

Java中經常會出現NullException,為了檢驗空值異常,程序員經常需要添加許多與業務邏輯無關的檢測代碼,這既破壞了代碼美感,也耗費了寶貴的開發時間,因此Java8中仿照谷歌開源庫Guava使用了Optional類,此類提供了有效的接口用於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!" ) );

Stream

Stream也是Java中非常重要的一個特性,在Java文檔中這樣定義Stream:

A sequence of elements supporting sequential and parallel aggregate operations.

翻譯一下,即:

  1. 元素的集合,這也使得Stream類似於Iterator;

  2. 可以順序或是並行的對原數據進行操作。

顯而易見,Stream的設計源於分治法,學過並行計算框架MapReduce或Fork/Join的同學更容易理解。


分享到:


相關文章: