1. 程式人生 > >jdk版本更新的新特性總結

jdk版本更新的新特性總結

jdk1.5新特性

1.靜態匯入(import static

import語句可以匯入一個類或是某個包中的所有類。

import static 語句可以匯入一個類中的某個靜態方法或是所有靜態方法。

例如:

Math類提供了很多於數學運算的靜態方法,通常情況下我們是以Math.abs();這樣的方式來進行呼叫函式的。但是我們可不可以只寫出adb();

JDK1.5之後,可以使用import static 語句匯入一個類中的某個靜態方法或是所有靜態方法。這是JDK1.5的新特性之一。

例如:

import static java.lang.Math.abs;就可以直接寫一個abs();

函式。

import static java.lang.Math.*; 就可以直接呼叫Math類中的所有靜態方法。

2.泛型(Generic

JDK1.5之前,在Java集合容器中(如:List)可以講任何型別的物件加入到其中,此時被加入的物件被視為Object來看待。當從集合容器取出物件時,需要程式設計師自行保證物件型別的強制轉換。如下:

JDK1.5新特性 - CH - 已經開始…

這段程式碼中很顯然List物件中的型別不匹配,但JDK1.5之前會編譯通過,執行時才會報錯,這樣在開發過程中很不好。所以JDK1.5引入了泛型(Generic)的概念。在看下面的程式碼:

JDK1.5新特性 - CH - 已經開始…

    泛型的引入在很大程度上避免了程式設計師自行保證集合容器中存取資料的強制轉換。

3.For-Each迴圈(增強型for迴圈)

JDK1.5中,For-Each迴圈加入簡化了集合的遍歷。假設我們要遍歷一個集合對其中的元素進行一些處理。典型的程式碼為:

JDK1.5新特性 - CH - 已經開始…

4.自動裝包/拆包(Autoboxing/unboxing

自動裝包/拆包大大方便了基本型別資料和它們包裝類地使用。  自動裝包:基本型別自動轉為包裝類.(int>>Integer)  自動拆包:包裝類自動轉為基本型別.(Integer>>int)

5.列舉(Enums

JDK1.5加入了一個全新型別的列舉型別。為此JDK1.5引入了一個新關鍵字enmu. 我們可以這樣來定義一個列舉型別。

如下:

JDK1.5新特性 - CH - 已經開始…

之後,可以這樣使用:

Gender gender = Gender.male;

可以對列舉進行遍歷,列舉型別提供了兩個靜態方法values()valueOf()

JDK1.5新特性 - CH - 已經開始…

6.可變引數(Varargs

可變引數使程式設計師可以宣告一個接受可變數目引數的方法(類似於多個方法過載,只不過是可變引數提供一個方法實現多個方法的過載,變得只是方法其中的引數)

注意可變引數必須是函式宣告中的最後一個引數。

比如:我們編寫一個簡單的列印方法,以傳統的方式實現方法過載:

JDK1.5新特性 - CH - 已經開始…

下面使用可變引數來實現這些方法的過載:

JDK1.5新特性 - CH - 已經開始…

呼叫方法:

Write("abc",123,new ArrayList());  // 當然其中的引數可以是任意型別,任意多個

 // 這就很方便的實現了方法過載 

輸出:

java.lang.Stringjava.lang.Integerjava.util.ArrayList

jdk1.6新特性

1.DestTop類和SystemTray

前者用於排程作業系統中的一些功能,例如:

· 可以開啟系統預設瀏覽器指定的URL地址;

· 開啟系統預設郵件客戶端給指定的郵箱發信息;

· 用預設程式開啟或編輯檔案;

· 用系統預設的印表機列印文件。

後者可用來在系統托盤區建立一個托盤程式

2.使用JAXB2來實現物件與XML之間的對映

JAXBJava Architecture for XML Binding的簡寫。JAXB是一個業界的標準,是一項可以根據XML Schema產生Java類的技術JAXB提供了快速而簡便的方法將XML模式繫結到Java表示,從而使得Java開發者在Java應用程式中能方便地結合XML資料和處理函式。原來JAXBJava EE的一部分,在JDK6中,SUN將其放到了Java SE

3.StAX

StAXJDK1.6中除了DOMSAX之外的有一種處理XML文件的API

StAXThe Streaming API for XML的縮寫由於JDK6.0中的JAXB2JAX-WS 2.0都會用到StAX所以Sun決定把StAX加入到JAXP家族當中來,並將JAXP的版本升級到1.4. 

JDK6裡面JAXP的版本就是1.4JAXPJava API for XML Processing的英文字頭縮寫,中文含義是:用於XML文件處理的使用Java語言編寫的程式設計介面。

4.使用Complier API

現在我們可以用JDK1.Compiler API動態編譯Java原始檔Compiler API結合反射功能就可以實現動態的產生Java程式碼並編譯執行這些程式碼,有點動態語言的特徵。

這個特性對於某些需要用到動態編譯的應用程式相當有用, 比如JSP Web Server,當我們手動修改JSP後,是不希望需要重啟Web Server才可以看到效果的,這時候我們就可以用Compiler API來實現動態編譯JSP檔案

5.輕量級的Http Server API

JDK6 提供了一個簡單的Http Server API,據此我們可以構建自己的嵌入式Http Server,支援HttpHttps協議,提供了HTTP1.1的部分實現,沒有被實現的那部分可以通過擴充套件已有的Http Server API來實現

6.插入式註解處理API(Pluggable Annotation Processing API)

JSR JSRJava Specification Requests的縮寫,意思是Java 規範請求Annotation Processor在編譯期間而不是執行期間處理Annotation, Annotation Processor相當於編譯器的一個外掛,所以稱為插入式註解處理

7.Console開發控制檯程式

JDK6中提供了java.io.Console 類專用來訪問基於字元的控制檯裝置你的程式如果要與Windows下的cmd或者Linux下的Terminal互動,就可以用Console類代勞

8.對指令碼語言的支援

: ruby, groovy, javascript

9.Common Annotations

Common annotations原本是Java EE 5.0規範的一部分,現在SUN把它的一部分放到了Java SE 6.0隨著Annotation元資料功能加入到Java SE 5.0裡面,很多Java 技術(比如EJB,Web Services)都會用Annotation部分代替XML檔案來配置執行引數保證Java SEJava EE 各種技術的一致性.

jdk1.7新特性

1,switch中可以使用字串了
String s = "test";   
switch (s) {   
case "test" :   
     System.out.println("test"); 
case "test1" :   
    System.out.println("test1"); 
    break ;   
default :   
    System.out.println("break"); 
    break ;   
}

2.運用List<String> tempList = new ArrayList<>(); 即泛型例項化型別自動推斷
3.語法上支援集合,而不一定是陣列

final List<Integer> piDigits = [ 1,2,3,4,5,8 ];   
4.新增一些取環境資訊的工具方法

File System.getJavaIoTempDir() // IO臨時資料夾

File System.getJavaHomeDir() // JRE的安裝目錄

File System.getUserHomeDir() // 當前使用者目錄

File System.getUserDir() // 啟動Java程序時所在的目錄5

5.Boolean型別反轉,空指標安全,參與位運算

Boolean Booleans.negate(Boolean booleanObj)

True => False , False => True, Null => Null

boolean Booleans.and(boolean[] array)

boolean Booleans.or(boolean[] array)

boolean Booleans.xor(boolean[] array)

boolean Booleans.and(Boolean[] array)

boolean Booleans.or(Boolean[] array)

boolean Booleans.xor(Boolean[] array)

6.兩個char間的equals 
boolean Character.equalsIgnoreCase(char ch1, char ch2)
7.安全的加減乘除 
int Math.safeToInt(long value)

int Math.safeNegate(int value)

long Math.safeSubtract(long value1, int value2)

long Math.safeSubtract(long value1, long value2)

int Math.safeMultiply(int value1, int value2)

long Math.safeMultiply(long value1, int value2)

long Math.safeMultiply(long value1, long value2)

long Math.safeNegate(long value)

int Math.safeAdd(int value1, int value2)

long Math.safeAdd(long value1, int value2)

long Math.safeAdd(long value1, long value2)

int Math.safeSubtract(int value1, int value2)

8.map集合支援併發請求,且可以寫成 Map map = {name:"xxx",age:18};


jdk1.8新特性

一、介面的預設方法

Java 8允許我們給介面新增一個非抽象的方法實現,只需要使用 default關鍵字即可,這個特徵又叫做擴充套件方法,示例如下:

複製程式碼 程式碼如下:
interface Formula {
    double calculate(int a);

    default double sqrt(int a) {
        return Math.sqrt(a);
    }
}


Formula介面在擁有calculate方法之外同時還定義了sqrt方法,實現了Formula介面的子類只需要實現一個calculate方法,預設方法sqrt將在子類上可以直接使用。
複製程式碼 程式碼如下:
Formula formula = new Formula() {
    @Override
    public double calculate(int a) {
        return sqrt(a * 100);
    }
};

formula.calculate(100);     // 100.0
formula.sqrt(16);           // 4.0


文中的formula被實現為一個匿名類的例項,該程式碼非常容易理解,6行程式碼實現了計算 sqrt(a * 100)。在下一節中,我們將會看到實現單方法介面的更簡單的做法。

譯者注: 在Java中只有單繼承,如果要讓一個類賦予新的特性,通常是使用介面來實現,在C++中支援多繼承,允許一個子類同時具有多個父類的介面與功能,在其他語言中,讓一個類同時具有其他的可複用程式碼的方法叫做mixin。新的Java 8 的這個特新在編譯器實現的角度上來說更加接近Scala的trait。 在C#中也有名為擴充套件方法的概念,允許給已存在的型別擴充套件方法,和Java 8的這個在語義上有差別。

二、Lambda 表示式

首先看看在老版本的Java中是如何排列字串的:

複製程式碼 程式碼如下:
List<String> names = Arrays.asList("peter", "anna", "mike", "xenia");

Collections.sort(names, new Comparator<String>() {
    @Override
    public int compare(String a, String b) {
        return b.compareTo(a);
    }
});


只需要給靜態方法 Collections.sort 傳入一個List物件以及一個比較器來按指定順序排列。通常做法都是建立一個匿名的比較器物件然後將其傳遞給sort方法。

在Java 8 中你就沒必要使用這種傳統的匿名物件的方式了,Java 8提供了更簡潔的語法,lambda表示式:

複製程式碼 程式碼如下:
Collections.sort(names, (String a, String b) -> {
    return b.compareTo(a);
});

看到了吧,程式碼變得更段且更具有可讀性,但是實際上還可以寫得更短:
複製程式碼 程式碼如下:
Collections.sort(names, (String a, String b) -> b.compareTo(a));

對於函式體只有一行程式碼的,你可以去掉大括號{}以及return關鍵字,但是你還可以寫得更短點:
複製程式碼 程式碼如下:
Collections.sort(names, (a, b) -> b.compareTo(a));

Java編譯器可以自動推匯出引數型別,所以你可以不用再寫一次型別。接下來我們看看lambda表示式還能作出什麼更方便的東西來:

三、函式式介面

Lambda表示式是如何在java的型別系統中表示的呢?每一個lambda表示式都對應一個型別,通常是介面型別。而“函式式介面”是指僅僅只包含一個抽象方法的介面,每一個該型別的lambda表示式都會被匹配到這個抽象方法。因為 預設方法 不算抽象方法,所以你也可以給你的函式式介面新增預設方法。

我們可以將lambda表示式當作任意只包含一個抽象方法的介面型別,確保你的介面一定達到這個要求,你只需要給你的介面新增 @FunctionalInterface 註解,編譯器如果發現你標註了這個註解的介面有多於一個抽象方法的時候會報錯的。

示例如下:

複製程式碼 程式碼如下:
@FunctionalInterface
interface Converter<F, T> {
    T convert(F from);
}
Converter<String, Integer> converter = (from) -> Integer.valueOf(from);
Integer converted = converter.convert("123");
System.out.println(converted);    // 123

需要注意如果@FunctionalInterface如果沒有指定,上面的程式碼也是對的。

譯者注 將lambda表示式對映到一個單方法的介面上,這種做法在Java 8之前就有別的語言實現,比如Rhino JavaScript直譯器,如果一個函式引數接收一個單方法的介面而你傳遞的是一個function,Rhino 直譯器會自動做一個單介面的例項到function的介面卡,典型的應用場景有 org.w3c.dom.events.EventTarget 的addEventListener 第二個引數 EventListener。

四、方法與建構函式引用

前一節中的程式碼還可以通過靜態方法引用來表示:

複製程式碼 程式碼如下:
Converter<String, Integer> converter = Integer::valueOf;
Integer converted = converter.convert("123");
System.out.println(converted);   // 123

Java 8 允許你使用 :: 關鍵字來傳遞方法或者建構函式引用,上面的程式碼展示瞭如何引用一個靜態方法,我們也可以引用一個物件的方法:
複製程式碼 程式碼如下:
 converter = something::startsWith;
String converted = converter.convert("Java");
System.out.println(converted);    // "J"

接下來看看建構函式是如何使用::關鍵字來引用的,首先我們定義一個包含多個建構函式的簡單類:
複製程式碼 程式碼如下:
class Person {
    String firstName;
    String lastName;

    Person() {}

    Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}


接下來我們指定一個用來建立Person物件的物件工廠介面:
複製程式碼 程式碼如下:
interface PersonFactory<P extends Person> {
    P create(String firstName, String lastName);
}

這裡我們使用建構函式引用來將他們關聯起來,而不是實現一個完整的工廠:
複製程式碼 程式碼如下:
PersonFactory<Person> personFactory = Person::new;
Person person = personFactory.create("Peter", "Parker");

我們只需要使用 Person::new 來獲取Person類建構函式的引用,Java編譯器會自動根據PersonFactory.create方法的簽名來選擇合適的建構函式。

五、Lambda 作用域

在lambda表示式中訪問外層作用域和老版本的匿名物件中的方式很相似。你可以直接訪問標記了final的外層區域性變數,或者例項的欄位以及靜態變數。

六、訪問區域性變數

我們可以直接在lambda表示式中訪問外層的區域性變數:

複製程式碼 程式碼如下:
final int num = 1;
Converter<Integer, String> stringConverter =
        (from) -> String.valueOf(from + num);

stringConverter.convert(2);     // 3


但是和匿名物件不同的是,這裡的變數num可以不用宣告為final,該程式碼同樣正確:
複製程式碼 程式碼如下:
int num = 1;
Converter<Integer, String> stringConverter =
        (from) -> String.valueOf(from + num);

stringConverter.convert(2);     // 3


不過這裡的num必須不可被後面的程式碼修改(即隱性的具有final的語義),例如下面的就無法編譯:
複製程式碼 程式碼如下:
int num = 1;
Converter<Integer, String> stringConverter =
        (from) -> String.valueOf(from + num);
num = 3;

在lambda表示式中試圖修改num同樣是不允許的。

七、訪問物件欄位與靜態變數

和本地變數不同的是,lambda內部對於例項的欄位以及靜態變數是即可讀又可寫。該行為和匿名物件是一致的:

複製程式碼 程式碼如下: class Lambda4 {
    static int outerStaticNum;
    int outerNum;

    void testScopes() {
        Converter<Integer, String> stringConverter1 = (from) -> {
            outerNum = 23;
            return String.valueOf(from);
        };

        Converter<Integer, String> stringConverter2 = (from) -> {
            outerStaticNum = 72;
            return String.valueOf(from);
        };
    }
}



八、訪問介面的預設方法

還記得第一節中的formula例子麼,介面Formula定義了一個預設方法sqrt可以直接被formula的例項包括匿名物件訪問到,但是在lambda表示式中這個是不行的。
Lambda表示式中是無法訪問到預設方法的,以下程式碼將無法編譯:
複製程式碼 程式碼如下:
Formula formula = (a) -> sqrt( a * 100);
Built-in Functional Interfaces

JDK 1.8 API包含了很多內建的函式式介面,在老Java中常用到的比如Comparator或者Runnable介面,這些介面都增加了@FunctionalInterface註解以便能用在lambda上。
Java 8 API同樣還提供了很多全新的函式式介面來讓工作更加方便,有一些介面是來自Google Guava庫裡的,即便你對這些很熟悉了,還是有必要看看這些是