為什么選擇 Java 8 ?
【編者按】本文是 DZone 指南 Java 生態系統 的專題文章,作者Trisha Gee是Java資深工程師和布道者。在本文中,Trisha Gee闡述了Java 8的重要特性以及使用的原因,由 OneAPM工程師 翻譯。
以下為譯文
要點速遞
- 在很多情況下,Java8 都能提升應用性能,而無需任何改變或性能調優。
- Lambda 表達式、 Streams API 以及現有類的新方法都是提高生產力的重要工具。
- Java8 新推出的 Optional 類型在處理 null 值時,能減少 NullPointerExceptions 的可能性,給開發者極大的靈活度。
去年年初,Java8 粉墨登場,現在 Java7 便已 行將就木 。在明年底 Java9 推出之前,Java8 是 Oracle 唯一支持的版本。然而,許多公司都將穩定性放在第一位,所以都還在用 Java7,甚至 Java6。
讓我們來了解一下 Java8 的一些特性,讓你在說服團隊升級 Java 版本時理由能更充分一些。
速度更快
可以取悅老板、滿足業務或運營人員的一大賣點是:Java8 運行應用時速度更快。通常,升級至 Java8 的應用都能得到速度上的提升,即便沒有做任何改變或調優。對于為了迎合特定 JVM 而做出調整的應用,這或許并不適用。但 Java8 性能更優的理由還有很多:
常見數據結構的性能提升 :對 廣受歡迎的 HashMap 進行的基準測試 表明,它們在 Java8 中的性能更好。這種提升非常吸引人——你無需學習新的 Streams API 或 Lambda 語法,甚至不需要改變現有的代碼,就能提升應用的性能。
垃圾回收器提升 :通常,Java 應用性能取決于垃圾回收的效率。的確,糟糕的垃圾回收會很大程度上影響應用性能。Java8 對垃圾回收做了很多改變,能有效提升性能并簡化調優。最為人熟知的改變是 PermGen 的移除與 Metaspace 的引入。
Fork/Join 速度提升 : fork/join 框架是在 Java7 中首次引入的,目的是簡化使用 JVM 的并發程序。Java8 中投入了很多努力進一步提升該框架。現在,fork/join 在 Streams API 中用于并發操作。
此外,Java8 中還包含 諸多改進 以支持并發。Oracle 在 JDK 8 中總結了這些性能提升。
代碼行更少
Java 經常被人們詬病其樣本代碼太多。為此,Java8 新的 API 采用了更具功能性的方式,專注于實現什么而不是如何實現。
Lambda 表達式
Java8 中的 Lambda 表達式 不僅是 Java 已有的匿名內部類—— Java8 推出之前傳遞行為的方法之外的語法糖衣。Lambda 表達式采用了 Java 7 的內部改變 ,因此運用起來相當流暢。想了解如何使用 Lambda 表達式簡化代碼,請繼續閱讀。
集合新方法介紹
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 為 Map 與 List 都添加了新方法。你可以了解一下這些新方法,看它們能節省多少行代碼。
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()); }
上面的做法不僅代碼行更少,而且描述性更強——后來的開發者讀到這段代碼能夠輕易理解:1、代碼從書中獲取作者姓名。2、只在意從未出現過的作者。3、返回的列表按照作者姓氏排序。將 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,J VM 會將此運算分解為不同的任務 ,使用 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 對業務、現有的應用以及期望提高生產力的開發者都好好多。
原文鏈接: Why Java 8? (責編/仲浩)