Java 5到Java8 的發展

Java 5到Java8 的發展

JDK 5

自動裝箱與拆箱

JDK1.5 爲每個基本數據類型定義了一個封裝類。使 java 中的基本數據類型也有本身的對象javascript

int -->Integer
double --> Double
long --> Long
char --> Character
float --> Float
boolean --> Boolean
short --> Short
byte -- > Byte
  • 自動裝包:將基本類型轉換成爲對象,例如:int --> Integer
  • 自動拆包:將對象轉換成爲基本數據類型,例如:Integer --> int

對於 JDK1.5 以前集合總不能存放基本數據類型的問題,如今也可以解決。java

枚舉

枚舉是 JDK1.5 推出的一個比較重要的特性。其關鍵字爲 enum
例如:定義表明交通燈的枚舉程序員

public enum MyEnum{    
    RED,GREEN,YELLOW
}

靜態導入

  • 優勢:使用靜態導入可使被導入類的全部靜態變量和靜態方法在當前類直接可見,使用這些靜態成員無需再給出他們的類名。
  • 缺點:過分使用會下降代碼的可讀性

可變參數

在 JDK1.5 之前,當咱們要爲一個方法傳遞多個類型相同的參數時,
咱們有兩種方法解決編程

  1. 直接傳遞一個數組過去
  2. 有多少個參數就傳遞多少個參數。

例如:數組

public void printColor(String red,String green,String yellow){ 
}

或者瀏覽器

public void printColor(String[] colors){}

這樣編寫方法參數雖然可以實現咱們想要的效果,可是,這樣是否是有點麻煩呢?
再者,若是參數個數不肯定,咱們怎麼辦呢?Java JDK1.5 爲咱們提供的可變參數就可以完美的解決這個問題.ruby

例如:微信

public void printColor(String... colors){}

若是參數的類型相同,那麼可使用 類型+三個點 ,後面跟一個參數名稱的形式。
這樣的好處就是,只要參數類型相同,不管傳遞幾個參數都沒有限制
注意:可變參數必須是參數列表的最後一項(該特性對對象和基本數據類型都適用)多線程

泛型

//給集合指定存入類型,上面這個集合在存入數據的時候必須存入String類型的數據,不然編譯器會報錯List<String> strs = new ArrayList<String>();

「泛型」 意味着編寫的代碼能夠被不一樣類型的對象所重用。閉包

可見泛型的提出是爲了編寫重用性更好的代碼。

泛型的本質是參數化類型,也就是說所操做的數據類型被指定爲一個參數。

好比常見的集合類 LinkedList,其實現的接口名後有個特殊的部分 <>,並且它的成員的類型 Link 也包含一個 <>,這個符號的就是類型參數,它使得在運行中,建立一個 LinkedList 時能夠傳入不一樣的類型,好比 new LinkedList,這樣它的成員存放的類型也是 String

For-Each 循環

例如上面這個集合咱們能夠經過 for-each 遍歷,這樣更加簡單清晰。

for(String s : strs){      
    System.out.println(s); 
}
注意:使用 for-each 遍歷集合時,要遍歷的集合必須實現了 Iterator 接口

線程併發庫

線程併發庫是 Java1.5 提出的關於多線程處理的高級功能,所在包:java.util.concurrent 包括

  1. 線程互斥工具類:LockReadWriteLock
  2. 線程通訊:Condition
  3. 線程池:ExecutorService
  4. 同步隊列:ArrayBlockingQueue
  5. 同步集合:ConcurrentHashMapCopyOnWriteArrayList
  6. 線程同步工具:Semaphore

JDK 6

Desktop 類和 SystemTray 類

前者能夠用來打開系統默認瀏覽器瀏覽指定的 URL,打開系統默認郵件客戶端給指定的郵箱發郵件,用默認應用程序打開或編輯文件 (好比,用記事本打開以 txt 爲後綴名的文件),用系統默認的打印機打印文檔;後者能夠用來在系統托盤區建立一個托盤程序。

使用 Compiler API

如今咱們能夠用 JDK1.6 的 Compiler API(JSR 199) 去動態編譯 Java 源文件,Compiler API 結合反射功能就能夠實現動態的產生 Java 代碼並編譯執行這些代碼,有點動態語言的特徵。

這個特性對於某些須要用到動態編譯的應用程序至關有用,好比 JSP Web Server,當咱們手動修改 JSP 後,是不但願須要重啓 Web Server 才能夠看到效果的,這時候咱們就能夠用 Compiler API 來實現動態編譯 JSP 文件。

固然,如今的 JSP Web Server 也是支持 JSP 熱部署的,如今的 JSP Web Server 經過在運行期間經過 Runtime.exec 或 ProcessBuilder 來調用 javac 來編譯代碼,這種方式須要咱們產生另外一個進程去作編譯工做,不夠優雅並且容易使代碼依賴與特定的操做系統;

Compiler API 經過一套易用的標準的 API 提供了更加豐富的方式去作動態編譯,並且是跨平臺的。

輕量級 Http Server API

JDK1.6 提供了一個簡單的 Http Server API,據此咱們能夠構建本身的嵌入式 Http Server,它支持 Http 和 Https 協議,提供了 HTTP1.1 的部分實現,沒有被實現的那部分能夠經過擴展已有的 Http Server API 來實現,程序員必須本身實現 HttpHandler 接口,HttpServer 會調用 HttpHandler 實現類的回調方法來處理客戶端請求,在這裏,咱們把一個 Http 請求和它的響應稱爲一個交換,包裝成 HttpExchange 類,HttpServer 負責將 HttpExchange 傳給 HttpHandler 實現類的回調方法。

用 Console 開發控制檯程序

JDK1.6 中提供了 java.io.Console 類專用來訪問基於字符的控制檯設備。
你的程序若是要與 Windows 下的 cmd 或者 Linux 下的 Terminal 交互,就能夠用 Console 類代勞。
但咱們不老是能獲得可用的 Console,一個 JVM 是否有可用的 Console 依賴於底層平臺和 JVM 如何被調用。
若是 JVM 是在交互式命令行 (好比 Windows 的 cmd) 中啓動的,而且輸入輸出沒有重定向到另外的地方,那麼就能夠獲得一個可用的 Console 實例。

對腳本語言的支持

如:ruby,groovy,javascript。

JDK 7

數字變量對下滑線的支持

JDK1.7 能夠在數值類型的變量裏添加下滑線。

例如:

int num = 1234_5678_9; 
float num2 = 222_33F; 
long num3 = 123_000_111L;

注意,有幾個地方是不能添加的:

  1. 數字的開頭和結尾
  2. 小數點先後
  3. F 或者 L 前

switch 對 String 的支持

String status = "orderState";     
switch (status) {   
    case "ordercancel":   
        System.out.println("訂單取消");   
        break;   
    case "orderSuccess":   
        System.out.println("預訂成功");   
        break;   
    default:   
        System.out.println("狀態未知");   
}

try-with-resource

  • try-with-resources 是一個定義了一個或多個資源的 try 聲明,這個資源是指程序處理完它以後須要關閉它的對象。
  • try-with-resources 確保每個資源在處理完成後都會被關閉。

可使用 try-with-resources 的資源有: 任何實現了 java.lang.AutoCloseable 接口 java.io.Closeable 接口的對象。

例如:

public static String readFirstLineFromFile(String path) throws IOException {   

    try (BufferedReader br = new BufferedReader(new FileReader(path))) {   
        return br.readLine();   
    }   
}

在 java 7 以及之後的版本里,BufferedReader 實現了 java.lang.AutoCloseable 接口。
因爲 BufferedReader 定義在 try-with-resources 聲明裏,不管 try 語句正常仍是異常的結束,
它都會自動的關掉。而在 java7 之前,你須要使用 finally 塊來關掉這個對象。

捕獲多種異常並用改進後的類型檢查來從新拋出異常

public static void first(){   
    try {   
        BufferedReader reader = new BufferedReader(new FileReader(""));   
        Connection con = null;   
        Statement stmt = con.createStatement();   
    } catch (IOException | SQLException e) {   
        //捕獲多個異常,e就是final類型的   
        e.printStackTrace();   
    }   
}

優勢:用一個 catch 處理多個異常,比用多個 catch 每一個處理一個異常生成的字節碼要更小更高效。

建立泛型時類型推斷

只要編譯器能夠從上下文中推斷出類型參數,你就能夠用一對空着的尖括號 <> 來代替泛型參數。
這對括號私下被稱爲菱形 (diamond)。 在 Java SE 7 以前,你聲明泛型對象時要這樣

List<String> list = new ArrayList<String>();

而在 Java SE7 之後,你能夠這樣

List<String> list = new ArrayList<>();

由於編譯器能夠從前面 (List) 推斷出推斷出類型參數,因此後面的 ArrayList 以後能夠不用寫泛型參數了,只用一對空着的尖括號就行。
固然,你必須帶着菱形 <>,不然會有警告的。
Java SE7 只支持有限的類型推斷:只有構造器的參數化類型在上下文中被顯著的聲明瞭,你纔可使用類型推斷,不然不行。

List<String> list = new ArrayList<>();
list.add("A"); 
//這個不行 
list.addAll(new ArrayList<>()); 
// 這個能夠 
List<? extends String> list2 = new ArrayList<>(); 
list.addAll(list2);

JDK 8

Lambda 表達式和函數式接口

Lambda 表達式(也稱爲閉包)是 Java 8 中最大和最使人期待的語言改變。它容許咱們將函數當成參數傳遞給某個方法,或者把代碼自己看成數據處理:函數式開發者很是熟悉這些概念。不少 JVM 平臺上的語言(Groovy、Scala 等)從誕生之日就支持 Lambda 表達式,可是 Java 開發者沒有選擇,只能使用匿名內部類代替 Lambda 表達式。

Lambda 的設計耗費了不少時間和很大的社區力量,最終找到一種折中的實現方案,能夠實現簡潔而緊湊的語言結構。最簡單的 Lambda 表達式可由逗號分隔的參數列表、-> 符號和語句塊組成。

Lambda 的設計者們爲了讓現有的功能與 Lambda 表達式良好兼容,考慮了不少方法,因而產生了函數接口這個概念。函數接口指的是隻有一個函數的接口,這樣的接口能夠隱式轉換爲 Lambda 表達式。java.lang.Runnable 和java.util.concurrent.Callable 是函數式接口的最佳例子。在實踐中,函數式接口很是脆弱:只要某個開發者在該接口中添加一個函數,則該接口就再也不是函數式接口進而致使編譯失敗。爲了克服這種代碼層面的脆弱性,並顯式說明某個接口是函數式接口,Java 8 提供了一個特殊的註解 @FunctionalInterface(Java 庫中的全部相關接口都已經帶有這個註解了)。

接口的默認方法和靜態方法

Java 8 使用兩個新概念擴展了接口的含義:默認方法和靜態方法。默認方法使得接口有點相似 traits,不過要實現的目標不同。默認方法使得開發者能夠在 不破壞二進制兼容性的前提下,往現存接口中添加新的方法,即不強制那些實現了該接口的類也同時實現這個新加的方法。

默認方法和抽象方法之間的區別在於抽象方法須要實現,而默認方法不須要。接口提供的默認方法會被接口的實現類繼承或者覆寫。

因爲 JVM 上的默認方法的實如今字節碼層面提供了支持,所以效率很是高。默認方法容許在不打破現有繼承體系的基礎上改進接口。該特性在官方庫中的應用是:給 java.util.Collection 接口添加新方法,如 stream()、parallelStream()、forEach() 和 removeIf() 等等。

儘管默認方法有這麼多好處,但在實際開發中應該謹慎使用:在複雜的繼承體系中,默認方法可能引發歧義和編譯錯誤。若是想了解更多細節,能夠參考官方文檔。

更好的類型推斷

Java 8 編譯器在類型推斷方面有很大的提高,在不少場景下編譯器能夠推導出某個參數的數據類型,從而使得代碼更爲簡潔。

參數 Value.defaultValue() 的類型由編譯器推導得出,不須要顯式指明。在 Java 7 中這段代碼會有編譯錯誤,除非使用 Value.defaultValue()

Optional

Java 應用中最多見的 bug 就是空指針異常。在 Java 8 以前,Google Guava 引入了 Optionals 類來解決 NullPointerException,從而避免源碼被各類 null 檢查污染,以便開發者寫出更加整潔的代碼。Java 8 也將 Optional 加入了官方庫。
Optional 僅僅是一個容易存放 T 類型的值或者 null。它提供了一些有用的接口來避免顯式的 null 檢查,能夠參考 Java 8 官方文檔瞭解更多細節。

若是 Optional 實例持有一個非空值,則 isPresent() 方法返回 true,不然返回 false;orElseGet() 方法,Optional 實例持有 null,則能夠接受一個 lambda 表達式生成的默認值;map() 方法能夠將現有的 Optional 實例的值轉換成新的值;orElse() 方法與 orElseGet() 方法相似,可是在持有 null 的時候返回傳入的默認值。

Stream

新增的 Stream API(java.util.stream)將生成環境的函數式編程引入了 Java 庫中。這是目前爲止最大的一次對 Java 庫的完善,以便開發者可以寫出更加有效、更加簡潔和緊湊的代碼。

Task 類有一個分數(或僞複雜度)的概念,另外還有兩種狀態:OPEN 或者 CLOSED。如今假設有一個 task 集合,首先看一個問題:在這個 task 集合中一共有多少個 OPEN 狀態的點?

在 Java 8 以前,要解決這個問題,則須要使用 foreach 循環遍歷 task 集合;可是在 Java 8 中能夠利用 steams 解決:包括一系列元素的列表,而且支持順序和並行處理。

final Collection<Task> tasks = Arrays.asList(
        new Task(Status.OPEN, 5),
        new Task(Status.OPEN, 13),
        new Task(Status.CLOSED, 8)
);

// 使用sum()計算全部 OPEN 任務
final long totalPointsOfOpenTasks = tasks
        .stream()
        .filter(task -> task.getStatus() == Status.OPEN)
        .mapToInt(Task::getPoints)
        .sum();

System.out.println("Total points: " + totalPointsOfOpenTasks);

首先,tasks 集合被轉換成 steam 表示;其次,在 steam 上的 filter 操做會過濾掉全部 CLOSED 的 task;第三,mapToInt 操做基於每一個 task 實例的Task::getPoints方法將 task 流轉換成 Integer 集合;最後,經過 sum 方法計算總和,得出最後的結果。

新的日期時間 API

Java 8 引入了新的 Date-Time API(JSR 310) 來改進時間、日期的處理。時間和日期的管理一直是最令 Java 開發者痛苦的問題。java.util.Date 和後來的 java.util.Calendar 一直沒有解決這個問題(甚至令開發者更加迷茫)。由於上面這些緣由,誕生了第三方庫 Joda-Time,能夠替代 Java 的時間管理 API。

Java 8 中新的時間和日期管理 API 深受 Joda-Time 影響,並吸取了不少 Joda-Time 的精華。

第一,新的 java.time 包包含了全部關於日期、時間、時區、Instant(跟日期相似可是精確到納秒)、duration(持續時間)和時鐘操做的類。新設計的 API 認真考慮了這些類的不變性(從 java.util.Calendar 吸收的教訓),若是某個實例須要修改,則返回一個新的對象。

第二,關注下 LocalDate 和 LocalTime 類。LocalDate 僅僅包含 ISO-8601 日曆系統中的日期部分;LocalTime 則僅僅包含該日曆系統中的時間部分。這兩個類的對象均可以使用 Clock 對象構建獲得。

第三,LocalDateTime 類包含了 LocalDate 和 LocalTime 的信息,可是不包含 ISO-8601 日曆系統中的時區信息。這裏有一些關於 LocalDate 和 LocalTime 的例子:

若是你須要特定時區的 data/time 信息,則可使用 ZoneDateTime,它保存有 ISO-8601 日期系統的日期和時間,並且有時區信息。

Nashorn JavaScript 引擎

Java 8 提供了新的 Nashorn JavaScript 引擎,使得咱們能夠在 JVM 上開發和運行 JS 應用。
Nashorn JavaScript 引擎是 javax.script.ScriptEngine 的另外一個實現版本,這類 Script 引擎遵循相同的規則,容許 Java 和 JavaScript 交互使用。

Base64

對 Base64 編碼的支持已經被加入到 Java 8 官方庫中,這樣不須要使用第三方庫就能夠進行 Base64 編碼。

歡迎轉載,轉載請註明出處! 獨立域名博客:flywill.cn 歡迎關注公衆微信號:Java小鎮V 分享本身的學習 & 學習資料 & 生活 想要交流的朋友也能夠加微信號備註入羣:EscUpDn
相關文章
相關標籤/搜索