爲何選擇 Java 8 ?

本文是 DZone 指南 Java 生態系統的專題文章。點擊連接可閱讀更多看法深入的文章、行業統計信息,系 OneAPM工程師編譯整理。html

爲何選擇Java8

要點速遞

  • 在不少狀況下,Java8 都能提高應用性能,而無需任何改變或性能調優。
  • Lambda 表達式、 Streams API 以及現有類的新方法都是提升生產力的重要工具。
  • Java8 新推出的 Optional 類型在處理 null 值時,能減小 NullPointerExceptions 的可能性,給開發者極大的靈活度。

去年年初,Java8 粉墨登場,如今 Java7 便已行將就木。在明年末 Java9 推出以前,Java8 是 Oracle 惟一支持的版本。然而,許多公司都將穩定性放在第一位,因此都還在用 Java7,甚至 Java6。java

讓咱們來了解一下 Java8 的一些特性,讓你在說服團隊升級 Java 版本時理由能更充分一些。express

速度更快

能夠取悅老闆、知足業務或運營人員的一大賣點是:Java8 運行應用時速度更快。一般,升級至 Java8 的應用都能獲得速度上的提高,即使沒有作任何改變或調優。對於爲了迎合特定 JVM 而作出調整的應用,這或許並不適用。但 Java8 性能更優的理由還有不少:api

常見數據結構的性能提高:對廣受歡迎的 HashMap 進行的基準測試代表,它們在 Java8 中的性能更好。這種提高很是吸引人——你無需學習新的 Streams API 或 Lambda 語法,甚至不須要改變現有的代碼,就能提高應用的性能。服務器

垃圾回收器提高:一般,Java 應用性能取決於垃圾回收的效率。的確,糟糕的垃圾回收會很大程度上影響應用性能。Java8 對垃圾回收作了不少改變,能有效提高性能並簡化調優。最爲人熟知的改變是 PermGen 的移除與 Metaspace 的引入數據結構

Fork/Join 速度提高fork/join 框架是在 Java7 中首次引入的,目的是簡化使用 JVM 的併發程序。Java8 中投入了不少努力進一步提高該框架。如今,fork/join 在 Streams API 中用於併發操做。併發

此外,Java8 中還包含諸多改進以支持併發。Oracle 在 JDK 8 中總結了這些性能提高。oracle

代碼行更少

Java 常常被人們詬病其樣本代碼太多。爲此,Java8 新的 API 採用了更具功能性的方式,專一於實現什麼而不是如何實現。框架

Lambda 表達式

Java8 中的 Lambda 表達式不只是 Java 已有的匿名內部類—— Java8 推出以前傳遞行爲的方法以外的語法糖衣。Lambda 表達式採用了 Java 7 的內部改變,所以運用起來至關流暢。想了解如何使用 Lambda 表達式簡化代碼,請繼續閱讀。ide

集合新方法介紹

Lambda 表達式與 Streams 多是 Java8 最大的兩個賣點,較少爲人知的是 Java 如今容許開發者給現有類添加新的方法,而無需爲了向後兼容性折中。這樣,新的方法,結合 Lambda 表達式,能在很大程序上簡化代碼。好比,咱們經常須要判斷 Map 中的某個成員是否已經存在,若是不存在則建立之。在 Java8 以前,你可能會這麼作:

private final Map<CustomerId, Customer> customers = new HashMap<>();

public void incrementCustomerOrders(CustomerId customerId) {
Customer customer = customers.get(customerId);
if (customer == null) {
    customer = new Customer(customerId);
    customers.put(customerId, customer);
}
customer.incrementOrders();
}

操做「檢查某個成員在 map 中是否存在,若不存在則添加之」是如此經常使用,Java 如今爲 Map 添加了一個新方法 computeIfAbsent 來支持這個操做。該方法的第二個參數是一個 Lambda 表達式,該表達式定義瞭如何建立缺乏的成員。

public void incrementCustomerOrders(CustomerId customerId) {
Customer customer = customers.computeIfAbsent(customerId,
       id -> new Customer(id));
customer.incrementOrders();
}

其實,Java8 還有一個新的特性,稱爲方法引用(method references),它能使咱們用更簡潔的代碼實現該功能:

public void incrementCustomerOrders(CustomerId customerId) {
Customer customer = customers.computeIfAbsent(customerId, Customer::new);
customer.incrementOrders();
}

Java8 爲 MapList 都添加了新方法。你能夠了解一下這些新方法,看它們能節省多少行代碼。

Streams API

Streams API 爲查詢、操縱數據提供了更多靈活度。這是一個很強大的功能。閱讀這些文章能對 Streams API 有更全面的瞭解。在大數據時代創建流暢的數據查詢會很是有趣,並且也是經常使用的操做。好比,你有一列書,你但願按照字母表順序排列這些書的做者名,且不含重複。

public List<Author> getAllAuthorsAlphabetically(List<Book> books) {
List<Author> authors = new ArrayList<>();
for (Book book : books) {
    Author author = book.getAuthor();
    if (!authors.contains(author)) {
        authors.add(author);
    }
}
Collections.sort(authors, new Comparator<Author>() {
    public int compare(Author o1, Author o2) {
        return o1.getSurname().compareTo(o2.getSurname());
    }
});
return authors;
}

在上面的代碼中,咱們首先遍歷這列書,若是書的做者從未在做者列表出現,則添加之。以後,咱們根據做者的姓氏按字母表順序對這些做者排序。這種排序操做正是 Streams 擅長解決的領域:

public List<Author> getAllAuthorsAlphabetically(List<Book> books) {
return books.Streams()
            .map(book -> book.getAuthor())
            .distinct()
            .sorted((o1, o2) -> o1.getSurname().compareTo(o2.getSurname()))
            .collect(Collectors.toList());
}

上面的作法不只代碼行更少,並且描述性更強——後來的開發者讀到這段代碼可以輕易理解:一、代碼從書中獲取做者姓名。二、只在乎從未出現過的做者。三、返回的列表按照做者姓氏排序。將 Streams API 與其餘新特性——方法引用(method references)比較器(Comparator)的新方法結合使用,能夠獲得更加簡潔的版本:

public List<Author> getAllAuthorsAlphabetically(List<Book> books) {
return books.Streams()
            .map(Book::getAuthor)
            .distinct()
            .sorted(Comparator.comparing(Author::getSurname))
            .collect(Collectors.toList());
}

這裏,排序方法按照做者姓氏排序,更加顯而易見了。

便於並行

此前咱們淺聊過更利於開箱即用的性能,除了前面提到過的特性,Java8 能更好地利用 CPU 內核。將前例中的 Streams 方法替換爲 parallelStreams,JVM 會將此運算分解爲不一樣的任務,使用 fork/join 將這些任務運行在多個核上。然而,並行化並非加速全部運算的魔法。並行化運算老是會帶來更多工做——分解運算,整合結果,所以沒法老是減小時間。可是,對適合並行化的例子,這麼作仍是很有效率的。

最大化減小 Null 指針

Java8 的另外一個新特性是全新的 Optional 類型。該類型的含義是「我可能有值,也多是 null。「這樣一來,API 就能夠區分可能爲 null 的返回值與絕對不會是 null 的返回值,從而最小化 NullPointerException 異常的發生概率。

Optional 最讚的用處是處理 null。例如,假設咱們要從一個列表中找一本特定的書,新建立的 findFirst() 方法會返回 Optional 類型的值,代表它沒法確保是否找到特定的值。有了這個可選擇的值,咱們接下來能夠決定,若是是 null 值要如何處理。若是想要拋出一個自定義的異常,咱們可使用 orElseThrow

public Book findBookByTitle(List<Book> books, String title) {
Optional<Book> foundBook = books.Streams()
       .filter(book -> book.getTitle().equals(title))
       .findFirst();
return foundBook.orElseThrow(() -> new BookNotFoundException("Did not find book with title " + title));
}

或者,你能夠返回其餘書:

return foundBook.orElseGet(() -> getRecommendedAlternativeBook(title));

或者,返回 Optional 類型,這樣,該方法的調用者能夠本身決定書沒找到時要怎麼作。

總結

Java8 做爲 Java 語言的一次重大發布,包含語法上的更改、新的方法與數據類型,以及一些能默默提高應用性能的隱性改善。Oracle 已經再也不支持 Java 7,所以許多公司都被迫向 Java8 轉移。好消息是,Java8 對業務、現有的應用以及指望提升生產力的開發者都好好多。原文地址

OneAPM for Java和監控,包括代碼級別性能問題的可見性、性能瓶頸的快速識別與追溯、真實用戶體驗監控、服務器監控和端到端的應用性能管理。想閱讀更多技術文章,請訪問 OneAPM 官方博客

相關文章
相關標籤/搜索