中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java 8的新特性以及改進有哪些

發布時間:2021-10-29 17:01:50 來源:億速云 閱讀:131 作者:柒染 欄目:編程語言

Java 8的新特性以及改進有哪些,相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。

這篇文章是對Java 8中即將到來的改進做一個面向開發者的綜合性的總結,JDK的這一特性將會在2013年9月份發布。

在寫這篇文章的時候,Java 8的開發工作仍然在緊張有序的進行中,語言特新和API仍然有可能改變,我會盡我最大的努力保持這份文檔跟得到Java 8的改動。

Java 8的預覽版,也就是 “Project Lambda”,現在可以從java.net下載到。

我使用了IntelliJ的預覽版做我的IDE,在我看來他是目前支持java 8特性最好的一個IDE,你可以從這里下載到.

由于我沒有找到Oracle發布的Java 8的官方文檔,所以目前Java 8的文檔還只有本地版本,等Oracle公開文檔的時候,我將會重新鏈接到官方文檔。

接口改善

現在接口里已經完全可以定義靜態方法了. 舉一個比較普遍的例子就是在java類庫中, 對于一些接口如Foo, 都會有一個有靜態方法的工具類Foos 來生成或者配合Foo對象實例來使用. 既然靜態方法可以存在于接口當中, 那么大多數情況下 Foos工具類完全可以使用接口中的公共方法來代理 (或者將Foos置成package-private).

除此之外更重要的就是, Java 8中接口可以定義默認的方法了.舉個例子,一個for-each循環的方法就可以加入到java.lang.Iterable中:

public default void forEach(Consumer<? super T> action) {      Objects.requireNonNull(action); for (T t : this) {          action.accept(t);      }  }

在過去,java類庫的接口中添加方法基本上是不可能的. 在接口中添加方法意味著破壞了實現了這個接口的代碼. 但是現在, 只要能夠提供一個正確明智的默認的方法的實現, java類庫的維護者就可以在接口中添加方法.

Java 8中, 大量的默認方法已經被添加到核心的JDK接口中了. 稍候我會詳細介紹它們.

為什么不能用默認方法來重載equals,hashCode和toString?

接口不能提供對Object類的任何方法的默認實現。特別是,這意味著從接口里不能提供對equals,hashCode或toString的默認實現。

這剛看起來挺奇怪的,但考慮到一些接口實際上是在文檔里定義他們的equals行為的。List接口就是一個例子了。因此,為什么不允許這樣呢?

Brian Goetz在這個問題上的冗長的回復里給出了4個原因。我這里只說其中一個,因為那個已經足夠說服我了:

它會變得更困難來推導什么時候該調用默認的方法。現在它變得很簡單了:如果一個類實現了一個方法,那總是優先于默認的實現的。一旦所有接口的實例都是Object的子類,所有接口實例都已經有對equals/hashCode/toString的非默認實現。因此,一個在接口上這些的默認版本都是沒用的,它也不會被編譯。

要看更多的話,看下由Brian Goetz寫的解釋: 對“允許默認方法來重載Object的方法”的回復

函數式接口

Java 8 引入的一個核心概念是函數式接口。如果一個接口定義個唯一一個抽象方法,那么這個接口就成為函數式接口。比如,java.lang.Runnable就是一個函數式接口,因為它只頂一個一個抽象方法:

public abstract void run();

留意到“abstract”修飾詞在這里是隱含的,因為這個方法缺少方法體。為了表示一個函數式接口,并非想這段代碼一樣一定需要“abstract”關鍵字。

默認方法不是abstract的,所以一個函數式接口里可以定義任意多的默認方法,這取決于你。

同時,引入了一個新的Annotation:@FunctionalInterface。可以把他它放在一個接口前,表示這個接口是一個函數式接口。加上它的接口不會被編譯,除非你設法把它變成一個函數式接口。它有點像@Override,都是聲明了一種使用意圖,避免你把它用錯。

Lambdas

一個函數式接口非常有價值的屬性就是他們能夠用lambdas來實例化。這里有一些lambdas的例子:

左邊是指定類型的逗號分割的輸入列表,右邊是帶有return的代碼塊:

(int x, int y) -> { return x + y; }

左邊是推導類型的逗號分割的輸入列表,右邊是返回值:

(x, y) -> x + y

左邊是推導類型的單一參數,右邊是一個返回值:

x -> x * x

左邊沒有輸入 (官方名稱: “burger arrow”),在右邊返回一個值:

() -> x

左邊是推導類型的單一參數,右邊是沒返回值的代碼塊(返回void):

x -> { System.out.println(x); }

靜態方法引用:

String::valueOf

非靜態方法引用:

Object::toString

繼承的函數引用:

x::toString

構造函數引用:

ArrayList::new

你可以想出一些函數引用格式作為其他lambda格式的簡寫。

方法引用 等價的lambda表達式 
String::valueOf x -> String.valueOf(x)
Object::toString x -> x.toString()
x::toString () -> x.toString()
ArrayList::new () -> new ArrayList<>()

當然,在Java里方法能被重載。類可以有多個同名但不同參數的方法。這同樣對構造方法有效。ArrayList::new能夠指向它的3個構造方法中任何一個。決定使用哪個方法是根據在使用的函數式接口。

一個lambda和給定的函數式接口在“外型”匹配的時候兼容。通過“外型”,我指向輸入、輸出的類型和聲明檢查異常。

給出兩個具體有效的例子:

Comparator<String> c = (a, b) -> Integer.compare(a.length(),                                                   b.length());

一個Comparator<String>的compare方法需要輸入兩個闡述,然后返回一個int。這和lambda右側的一致,因此這個任務是有效的。

Runnable r = () -> { System.out.println("Running!"); }

一個Runnable的run方法不需要參數也不會返回值。這和lambda右側一致,所以任務有效。

在抽象方法的簽名里的受檢查異常(如果存在)也很重要。如果函數式接口在它的簽名里聲明了異常,lambda只能拋出受檢查異常。

捕獲和非捕獲的Lambda表達式

當Lambda表達式訪問一個定義在Lambda表達式體外的非靜態變量或者對象時,這個Lambda表達式稱為“捕獲的”。比如,下面這個lambda表達式捕捉了變量x:

int x = 5; return y -> x + y;

為了保證這個lambda表達式聲明是正確的,被它捕獲的變量必須是“有效final”的。所以要么它們需要用final修飾符號標記,要么保證它們在賦值后不能被改變。

Lambda表達式是否是捕獲的和性能悄然相關。一個非不捕獲的lambda通常比捕獲的更高效,雖然這一點沒有書面的規范說明(據我所知),而且也不能為了程序的正確性指望它做什么,非捕獲的lambda只需要計算一次. 然后每次使用到它都會返回一個唯一的實例。而捕獲的lambda表達式每次使用時都需要重新計算一次,而且從目前實現來看,它很像實例化一個匿名內部類的實例。

lambdas不做的事

你應該記住,有一些lambdas不提供的特性。為了Java 8它們被考慮到了,但是沒有被包括進去,由于簡化以及時間限制的原因。

Non-final* 變量捕獲 - 如果一個變量被賦予新的數值,它將不能被用于lambda之中。”final”關鍵字不是必需的,但變量必須是“有效final”的(前面討論過)。這個代碼不會被編譯:

int count = 0;  List<String> strings = Arrays.asList("a", "b", "c");  strings.forEach(s -> {      count++; // error: can't modify the value of count });

例外的透明度 - 如果一個已檢測的例外可能從lambda內部拋出,功能性的接口也必須聲明已檢測例外可以被拋出。這種例外不會散布到其包含的方法。這個代碼不會被編譯:

void appendAll(Iterable<String> values, Appendable out) throws IOException { // doesn't help with the error values.forEach(s -> {          out.append(s); // error: can't throw IOException here // Consumer.accept(T) doesn't allow it });  }

有繞過這個的辦法,你能定義自己的功能性接口,擴展Consumer的同時通過像RuntimeException之類拋出 IOException。我試圖用代碼寫出來,但發現它令人困惑是否值得。

控制流程 (break, early return) -在上面的 forEach例子中,傳統的繼續方式有可能通過在lambda之內放置 ”return;”來實現。但是,沒有辦法中斷循環或者從lambda中通過包含方法的結果返回一個數值。例如:

final String secret = "foo"; boolean containsSecret(Iterable<String> values) {      values.forEach(s -> { if (secret.equals(s)) {              ??? // want to end the loop and return true, but can't }      });  }

進一步閱讀關于這些問題的資料,看看這篇Brian Goetz寫的說明:在 Block<T>中響應“已驗證例外”

為什么抽象類不能通過利用lambda實例化

抽象類,哪怕只聲明了一個抽象方法,也不能使用lambda來實例化。

下面有兩個類 Ordering 和 CacheLoader的例子,都帶有一個抽象方法,摘自于Guava 庫。那豈不是很高興能夠聲明它們的實例,像這樣使用lambda表達式?

Ordering<String> order = (a, b) -> ...;  CacheLoader<String, String> loader = (key) -> ...;

這樣做引發的最常見的爭論就是會增加閱讀lambda的難度。以這種方式實例化一段抽象類將導致隱藏代碼的執行:抽象類的構造方法。

另一個原因是,它拋出了lambda表達式可能的優化。在未來,它可能是這種情況,lambda表達式都不會計算到對象實例。放任用戶用lambda來聲明抽象類將妨礙像這樣的優化。

此外,有一個簡單地解決方法。事實上,上述兩個摘自Guava 庫的實例類已經證明了這種方法。增加工廠方法將lambda轉換成實例。

Ordering<String> order = Ordering.from((a, b) -> ...);  CacheLoader<String, String> loader = CacheLoader.from((key) -> ...);

要深入閱讀,請參看由 Brian Goetz所做的說明: response to “Allow lambdas to implement abstract classes”。

java.util.function

包概要:java.util.function

作為Comparator 和Runnable早期的證明,在JDK中已經定義的接口恰巧作為函數接口而與lambdas表達式兼容。同樣方式可以在你自己的代碼中定義任何函數接口或第三方庫。

但有特定形式的函數接口,且廣泛的,通用的,在之前的JD卡中并不存在。大量的接口被添加到新的java.util.function 包中。下面是其中的一些:

  • Function<T, R> -T作為輸入,返回的R作為輸出

  • Predicate<T> -T作為輸入,返回的boolean值作為輸出

  • Consumer<T> - T作為輸入,執行某種動作但沒有返回值

  • Supplier<T> - 沒有任何輸入,返回T

  • BinaryOperator<T> -兩個T作為輸入,返回一個T作為輸出,對于“reduce”操作很有用

這些最原始的特征同樣存在。他們以int,long和double的方式提供。例如:

  • IntConsumer -以int作為輸入,執行某種動作,沒有返回值

這里存在性能上的一些原因,主要釋在輸入或輸出的時候避免裝箱和拆箱操作。

java.util.stream

包匯總: java.util.stream

新的java.util.stream包提供了“支持在流上的函數式風格的值操作”(引用javadoc)的工具。可能活動一個流的最常見方法是從一個collection獲取:

Stream<T> stream = collection.stream();

一個流就像一個地帶器。這些值“流過”(模擬水流)然后他們離開。一個流可以只被遍歷一次,然后被丟棄。流也可以無限使用。

流能夠是 串行的 或者 并行的。 它們可以使用其中一種方式開始,然后切換到另外的一種方式,使用stream.sequential()或stream.parallel()來達到這種切換。串行流在一個線程上連續操作。而并行流就可能一次出現在多個線程上。

所以,你想用一個流來干什么?這里是在javadoc包里給出的例子:

int sumOfWeights = blocks.stream().filter(b -> b.getColor() == RED)                                    .mapToInt(b -> b.getWeight())                                    .sum();

注意:上面的代碼使用了一個原始的流,以及一個只能用在原始流上的sum()方法。下面馬上就會有更多關于原始流的細節。

流提供了流暢的API,可以進行數據轉換和對結果執行某些操作。流操作既可以是“中間的”也可以是“末端的”。

  •  -中間的操作保持流打開狀態,并允許后續的操作。上面例子中的filter和map方法就是中間的操作。這些操作的返回數據類型是流;它們返回當前的流以便串聯更多的操作。

  • 末端的 - 末端的操作必須是對流的最終操作。當一個末端操作被調用,流被“消耗”并且不再可用。上面例子中的sum方法就是一個末端的操作。

通常,處理一個流涉及了這些步驟:

  1. 從某個源頭獲得一個流。

  2. 執行一個或更多的中間的操作。

  3. 執行一個末端的操作。

可能你想在一個方法中執行所有那些步驟。那樣的話,你就要知道源頭和流的屬性,而且要可以保證它被正確的使用。你可能不想接受任意的Stream<T>實例作為你的方法的輸入,因為它們可能具有你難以處理的特性,比如并行的或無限的。

有幾個更普通的關于流操作的特性需要考慮:

  • 有狀態的 - 有狀態的操作給流增加了一些新的屬性,比如元素的唯一性,或者元素的最大數量,或者保證元素以排序的方式被處理。這些典型的要比無狀態的中間操作代價大。

  • 短路 - 短路操作潛在的允許對流的操作盡早停止,而不去檢查所有的元素。這是對無限流的一個特殊設計的屬性;如果對流的操作沒有短路,那么代碼可能永遠也不會終止。

對每個Sttream方法這里有一些簡短的,一般的描述。查閱javadoc獲取更詳盡的解釋。下面給出了每個操作的重載形式的鏈接。

中間的操作:

  • filter 1 - 排除所有與斷言不匹配的元素。

  • map 1 2 3 4 - 通過Function對元素執行一對一的轉換。

  • flatMap 1 2 3 4 5 - 通過FlatMapper將每個元素轉變為無或更多的元素。

  • peek 1 - 對每個遇到的元素執行一些操作。主要對調試很有用。

  • distinct 1 - 根據.equals行為排除所有重復的元素。這是一個有狀態的操作。

  • sorted 1 2 - 確保流中的元素在后續的操作中,按照比較器(Comparator)決定的順序訪問。這是一個有狀態的操作。

  • limit 1 - 保證后續的操作所能看到的最大數量的元素。這是一個有狀態的短路的操作。

  • substream 1 2 - 確保后續的操作只能看到一個范圍的(根據index)元素。像不能用于流的String.substring一樣。也有兩種形式,一種有一個開始索引,一種有一個結束索引。二者都是有狀態的操作,有一個結束索引的形式也是一個短路的操作。

末端的操作:

  • forEach 1 - 對流中的每個元素執行一些操作。

  • toArray 1 2 - 將流中的元素傾倒入一個數組。

  • reduce 1 2 3 - 通過一個二進制操作將流中的元素合并到一起。

  • collect 1 2 - 將流中的元素傾倒入某些容器,例如一個Collection或Map.

  • min 1 - 根據一個比較器找到流中元素的最小值。

  • max 1 -根據一個比較器找到流中元素的最大值。

  • count 1 - 計算流中元素的數量。

  • anyMatch 1 - 判斷流中是否至少有一個元素匹配斷言。這是一個短路的操作。

  • allMatch 1 - 判斷流中是否每一個元素都匹配斷言。這是一個短路的操作。

  • noneMatch 1 - 判斷流中是否沒有一個元素匹配斷言。這是一個短路的操作。

  • findFirst 1 - 查找流中的第一個元素。這是一個短路的操作。

  • findAny 1 - 查找流中的任意元素,可能對某些流要比findFirst代價低。這是一個短路的操作。

如 javadocs中提到的 , 中間的操作是延遲的(lazy)。只有末端的操作會立即開始流中元素的處理。在那個時刻,不管包含了多少中間的操作,元素會在一個傳遞中處理(通常,但并不總是)。(有狀態的操作如sorted() 和distinct()可能需要對元素的二次傳送。)

流試圖盡可能做很少的工作。有一些細微優化,如當可以判定元素已經有序的時候,省略一個sorted()操作。在包含limit(x) 或 substream(x,y)的操作中,有些時候對一些不會決定結果的元素,流可以避免執行中間的map操作。在這里我不準備實現公平判斷;它通過許多細微的但卻很重要的方法表現得很聰明,而且它仍在進步。

回到并行流的概念,重要的是要意識到并行不是毫無代價的。從性能的立場它不是無代價的,你不能簡單的將順序流替換為并行流,且不做進一步思考就期望得到相同的結果。在你能(或者應該)并行化一個流以前,需要考慮很多特性,關于流、它的操作以及數據的目標方面。例如:訪問順序確實對我有影響嗎?我的函數是無狀態的嗎?我的流有足夠大,并且我的操作有足夠復雜,這些能使得并行化是值得的嗎?

有針對int,long和double的專業原始的Stream版本:

  • IntStream

  • LongStream

  • DoubleStream

可以在眾多函數中,通過專業原始的map和flatMap函數,在一個stream對象與一個原始stream對象之間來回轉換。給幾個虛設例子:

List<String> strings = Arrays.asList("a", "b", "c");  strings.stream() //  Stream<String> .mapToInt(String::length) // IntStream .longs() //  LongStream .mapToDouble(x -> x / 10.0) // DoubleStream .boxed() //  Stream<Double> .mapToLong(x -> 1L) // LongStream .mapToObj(x -> "") //  Stream<String> ...

原始的stream也為獲得關于stream的基礎數據統計提供方法,那些stream是指作為數據結構的。你可以發現count, sum, min, max, 以及元素平均值全部是來自于一個終端的操作。

原始類型的剩余部分沒有原始版本,因為這需要一個不可接受的JDK數量的膨脹。IntStream, LongStream, 和 DoubleStream被認為非常有用應當被包含進去,其他的數字型原始stream可以由這三個通過擴展的原始轉換來表示。

在flatMap操作中使用的 FlatMapper 接口是具有一個抽象方法的功能性接口:

void flattenInto(T element, Consumer<U> sink);

在一個flatMap操作的上下文中,stream為你提供element和 sink,然后你定義該用element 和 sink做什么。element是指在stream中的當前元素,而sink代表當flatMap操作結束之后在stream中應該顯示些什么。例如:

Set<Color> colors = ...;  List<Person> people = ...;  Stream<Color> stream = people.stream().flatMap(      (Person person, Consumer<Color> sink) -> { // Map each person to the colors they like. for (Color color : colors) { if (person.likesColor(color)) {                  sink.accept(color);              }          }      });

注意上面lambda中的參數類型是指定的。在大多數其它上下文中,你可以不需要指定類型,但這里由于FlatMapper的自然特性,編譯器需要你幫助判定類型。如果你在使用flatMap又迷惑于它為什么不編譯,可能是因為你沒有指定類型。

最令人感到困惑,復雜而且有用的終端stream操作之一是collect。它引入了一個稱為Collector的新的非功能性接口。這個接口有些難理解,但幸運的是有一個Collectors工具類可用來產生所有類型的有用的Collectors。例如:

List<String> strings = values.stream()                               .filter(...)                               .map(...)                               .collect(Collectors.toList());

如果你想將你的stream元素放進一個Collection,Map或String,那么Collectors可能具有你需要的。在javadoc中瀏覽那個類絕對是值得的。

泛型接口改進

建議摘要:JEP 101: 通用化目標-Type 接口

這是一個以前不能做到的,對編譯器判定泛型能力的努力改進。在以前版本的Java中有許多情形編譯器不能給某個方法計算出泛型,當方法處于嵌套的或串聯方法調用這樣的上下文的時候,即使有時候對程序員來說它看起來“很明顯”。那些情況需要程序員明確的指定一個“類型見證”(type witness)。它是一種通用的特性,但吃驚的是很少有Java程序員知道(我這么說是基于私下的交流并且閱讀了一些StackOverflow的問題)。它看起來像這樣:

// In Java 7: foo(Utility.<Type>bar());  Utility.<Type>foo().bar();

如果沒有類型見證,編譯器可能會將<Object>替代為泛型,而且如果需要的是一個更具體的類型,代碼將編譯失敗。

Java 8 極大的改進了這個狀況。在更多的案例中,它可以基于上下文計算出更多的特定的泛型類型。

// In Java 8: foo(Utility.bar());  Utility.foo().bar();

這項工作仍在發展中,所以我不確定建議中列出的例子有多少能真正包含進Java 8。希望是它們全部。

java.time

包概要: java.time

在Java8中新的 date/timeAPI存在于 java.time包中。如果你熟悉Joda Time,它將很容易掌握。事實上,我認為如此好的設計,以至于從未聽說過 Joda Time的人也能很容易的掌握。

幾乎在API中的任何東西都是永恒的,包括值類型和格式化 。對于Date域或者處理或處理本地線程日期格式化不必太過擔心。

與傳統的date/timeAPI的交叉是最小的。有一個清晰的分段:

  • Date.toInstant()

  • Date.from(Instant)

  • Calendar.toInstant()

新API對于像月份和每周的天數,喜歡枚舉類型更勝過整形常量。

那么,那是什么呢?包級別的javadocs 對額外類型的做出了非常好的闡述。我將對一些值得注意的部分做一些簡短的綱要。

非常有用的值類型:

  • Instant - 與java.util.Date相似

  • ZonedDateTime, ZoneId -時區很重要的時候使用

  • OffsetDateTime, OffsetTime, ZoneOffset -對UTC的偏移處理

  • Duration, Period - 但如果你想找到兩個日期之間的時間量,你可能會尋找ChronoUnit代替(見下文)

其他有用的類型:

  • DateTimeFormatter - 將日期類型轉換成字符串類型

  • ChronoUnit - 計算出兩點之間的時間量,例如ChronoUnit.DAYS.between(t1, t2)

  • TemporalAdjuster - 例如date.with(TemporalAdjuster.firstDayOfMonth())

大多數情況下,新的值類型由JDBC提供支持。有一小部分異常,如ZonedDateTime在SQL中沒有對應的(類型)。

集合API附件

實際上接口能夠定義默認方法允許了JDK作者加入大量的附件到集合API接口中。默認實現在核心接口里提供,而其他更有效或更好的重載實現被加入到可適用的具體類中。

這里是新方法的列表:

  • Iterable.forEach(Consumer)

  • Iterator.forEach(Consumer)

  • Collection.removeAll(Predicate)

  • Collection.spliterator()

  • Collection.stream()

  • Collection.parallelStream()

  • List.sort(Comparator)

  • Map.forEach(BiConsumer)

  • Map.replaceAll(BiFunction)

  • Map.putIfAbsent(K, V)

  • Map.remove(Object, Object)

  • Map.replace(K, V, V)

  • Map.replace(K, V)

  • Map.computeIfAbsent(K, Function)

  • Map.computeIfPresent(K, BiFunction)

  • Map.compute(K, BiFunction)

  • Map.merge(K, V, BiFunction)

  • Map.getOrDefault(Object, V)

同樣, Iterator.remove() 現在有一個默認的, 會拋出異常的實現,使得它稍微容易地去定義不可修改的迭代器。

Collection.stream()和Collection.parallelStream()是流API的主要門戶。有其他方法去生成流,但這些在以后會更為長用。

List.sort(Comparator)的附件有點怪異。以前排序一個ArrayList的方法是:

Collections.sort(list, comparator);

這代碼是你在Java7里唯一可選的,非常低效。它會復制list到一個數組里,排序這個數組,然后使用ListIterator來把數組插入到新list的新位置上。

List.sort(比較器)的默認實現仍然會做這個,但是具體的實現類可以自由的優化。例如,ArrayList.sort在ArrayList內部數組上調用了Arrays.sort。CopyOnWriteArrayList做了同樣的事情。

從這些新方法中獲得的不僅僅是性能。它們也具有更多的令人滿意的語義。例如, 對Collections.synchronizedList()排序是一個使用了list.sort的原子操作。你可以使用list.forEach對它的所有元素進行迭代,使之成為原子操作。

Map.computeIfAbsent使得操作類似多重映射的結構變得容易了:

// Index strings by length:   Map<Integer, List<String>> map = new HashMap<>(); for (String s : strings) {      map.computeIfAbsent(s.length(),                          key -> new ArrayList<String>())         .add(s);  } // Although in this case the stream API may be a better choice:   Map<Integer, List<String>> map = strings.stream()      .collect(Collectors.groupingBy(String::length));

增加并發API

  • ForkJoinPool.commonPool()

  • ConcurrentHashMap(v8)

  • 下面的形式有并行,順序,對象,整型,長整型和double型。

有太多的鏈接可以點擊,因此參看ConcurrentHashMap javadocs文檔以獲得更多信息。

  • ConcurrentHashMap.reduce&hellip;

  • ConcurrentHashMap.search&hellip;

  • ConcurrentHashMap.forEach&hellip;

  • ConcurrentHashMap.newKeySet()

  • ConcurrentHashMap.newKeySet(int)

  • CompletableFuture

  • StampedLock

  • LongAdder

  • LongAccumulator

  • DoubleAdder

  • DoubleAccumulator

  • CountedCompleter

  • Executors.newWorkStealingPool()

  • Executors.newWorkStealingPool(int)

  • 下面的形式有AtomicReference, AtomicInteger, AtomicLong, 和每一個原子數組的版本。

  • AtomicReference.getAndUpdate(UnaryOperator)

  • AtomicReference.updateAndGet(UnaryOperator)

  • AtomicReference.getAndAccumulate(V, UnaryOperator)

  • AtomicReference.accumulateAndGet(V, UnaryOperator)

ForkJoinPool.commonPool()是處理所有并行流操作的結構。當你 需要的時候,它是一個好而簡單的方式去獲得一個 ForkJoinPool/ExecutorService/Executor對象。ConcurrentHashMap<K, V>完全重寫。內部看起來它一點不像是Java7版本。從外部來看幾乎相同,除了它有大量批量操作方法:多種形式的減少搜索和forEach。
ConcurrentHashMap.newKeySet()提供了一個并發的java.util.Set實現。它基本上是 Collections.newSetFromMap(new ConcurrentHashMap<T, Boolean>())的另一種方式的重寫。

StampedLock是一種新型鎖的實現,很可能在大多數場景都可以替代ReentrantReadWriteLock。當作為一個簡單的讀寫鎖的時候,它比RRWL的性能要好。它也為“讀優化”提供了API,通過它你獲得了一個功能有點弱,但代價很小的讀操作鎖的版本,執行讀操作,然后檢查鎖是否被一個寫操作設定為無效。在Heinz Kabutz匯總的一系列幻燈片中,有更多關于這個類及其性能的細節(在這個系列幻燈片大約一半的地方開始的):“移相器和StampedLock演示“

CompletableFuture<T>是Future接口的一個非常棒的實現,它提供了無數執行(和串接)異步任務的方法。它特別依賴功能性的接口;lambdas是值得增加這個類的一個重要原因。如果你正在使用Guava的 Future工具,例如Futures, ListenableFuture, 和 SettableFuture,那么你可能會希望校驗CompletableFuture能否作為潛在的替代選擇。

IO/NIO API的新增內容

  • BufferedReader.lines()

  • Files.list(Path)

  • Files.walk(Path, int, FileVisitOption&hellip;)

  • Files.walk(Path, FileVisitOption&hellip;)

  • Files.find(Path, int, BiPredicate, FileVisitOption&hellip;)

  • Files.lines(Path, Charset)

  • DirectoryStream.entries()

簡單的說,這些API用于從文件和InputStreams獲取java.util.stream.Stream對象。不過它們與直接從常規的collection得到的流有些不同,它們引入了兩個概念:

  • UncheckedIOException - 當有IO錯誤時拋出這個異常,不過由于Iterator/Stream的簽名中不允許有IOException,所以它只能借助于unchecked異常。

  • CloseableStream - 可以(并且應該)定義在 try-with-resources 語句里面的流。

反射和annotation的改動

  • 類型annotation (JSR 308)

  • AnnotatedType

  • Repeatable

  • Method.getAnnotatedReturnType()

  • Field.getAnnotationsByType(Class)

  • Field.getAnnotatedType()

  • Constructor.getAnnotatedReturnType()

  • Parameter - 支持 parameter.getName(),等等。

Annotation允許在更多的地方被使用,例如List<@Nullable String>。受此影響最大的可能是那些靜態分析工具,如Sonar和FindBugs。

JSR 308的網站解釋了增加這些改動的動機,介紹的不錯: “類型Annotation (JSR 308) 和 Checker框架”

Nashorn JavaScript 引擎

提案的摘要: JEP 174: Nashorn JavaScript 引擎

我對Nashorn沒什么經驗,因而我對上面提案所描述的所知甚少。簡單的說,它是 Rhino 的接替者。Rhino 顯得有些老了,并且有點慢,開發者決定最好還是從頭做一個。

其他新增,涉及java.lang,java.util,和java.sql

  • ThreadLocal.withInitial(Supplier)

  • String.join(CharSequence, Charsequence&hellip;)

  • String.join(CharSequence, Iterable)

  • 下面的方法適用于所有數字的原語類型,并且作為這些類型的包裝(wrapper)類的三個方法。hashCode方法除外,它們的作用是作為BinaryOperatorin的reduce操作的參數。關于這些方法還有很多的鏈接,更多的內容,參考 Integer, Long, Double, Float, Byte, Short, 和 Character 的javadoc。

    • Primitive.min(primitive, primitive);

    • Primitive.max(primitive, primitive);

    • Primitive.sum(primitive, primitive);

    • Primitive.hashCode(primitive)

  • 同樣,下面新增的 Boolean 的方法可用于BinaryOperator<Boolean>:

    • Boolean.logicalAnd(boolean, boolean)

    • Boolean.logicalOr(boolean, boolean)

    • Boolean.logicalXor(boolean, boolean)

  • Optional

  • OptionalInt

  • OptionalLong

  • OptionalDouble

  • Base64

  • StringJoiner

  • Spliterator

  • Spliterators

  • Comparator.reverseOrder()

  • Comparator.thenComparing(Comparator)

  • Comparator.thenComparing(Function, Comparator)

  • Comparator.thenComparing(Function)

  • Comparator.thenComparing(ToIntFunction)

  • Comparator.thenComparing(ToLongFunction)

  • Comparator.thenComparing(ToDoubleFunction)

  • Comparators

  • 下面的方法適用于數組,支持T[], int[], long[], double[]。關于這些方法有很多鏈接,更多信息參考 Arrays 的javadoc。

    • Arrays.spliterator(array)

    • Arrays.spliterator(array, int, int)

    • Arrays.stream(array)

    • Arrays.stream(array, int, int);

    • Arrays.parallelStream(array)

    • Arrays.parallelStream(array, int, int);

    • Arrays.setAll(array, IntFunction)

    • Arrays.parallelSetAll(array, IntFunction)

  • Math.toIntExact(long)

  • Math.addExact(int, int)

  • Math.subtractExact(int, int)

  • Math.multiplyExact(int, int)

  • Math.floorDiv(int, int)

  • Math.floorMod(int, int)

  • Math.addExact(long, long)

  • Math.subtractExact(long, long)

  • Math.multiplyExact(long, long)

  • Math.floorDiv(long, long)

  • Math.floorMod(long, long)

  • Integer.toUnsignedLong(int)

  • Integer.toUnsignedString(int)

  • Integer.toUnsignedString(int, int)

  • Integer.parseUnsignedInt(String)

  • Integer.parseUnsignedInt(String, int)

  • Integer.compareUnsigned(int, int)

  • Long.toUnsignedString(long, int)

  • Long.toUnsignedString(long)

  • Long.parseUnsignedLong(String, int)

  • Long.parseUnsignedLong(String)

  • Long.compareUnsigned(long, long)

  • Long.divideUnsigned(long, long)

  • Long.remainderUnsigned(long, long)

  • BigInteger.longValueExact()

  • BigInteger.intValueExact()

  • BigInteger.shortValueExact()

  • BigInteger.byteValueExact()

  • Objects.isNull(Object) - 可用作謂詞,例如stream.anyMatch(Objects::isNull)

  • Objects.nonNull(Object) - 可用作謂詞,stream.filter(Objects::nonNull)

  • Random.ints()

  • Random.longs()

  • Random.doubles()

  • Random.gaussians()

  • BitSet.stream()

  • IntSummaryStatistics

  • LongSummaryStatistics

  • DoubleSummaryStatistics

  • Logger的雜項新增

  • Locale的雜項新增

  • ResultSet的雜項新增

這里可以介紹的太多了,只能挑一些最需要注意的項目。

ThreadLocal.withInitial(Supplier<T>) 可以在定義thread-local變量時更好的進行初始化。之前你初始化變量時是這樣的:

ThreadLocal<List<String>> strings = new ThreadLocal<List<String>>() { @Override protected List<String> initialValue() { return new ArrayList<>();          }      };

現在則是這樣:

ThreadLocal<List<String>> strings =      ThreadLocal.withInital(ArrayList::new);

stream的API的返回值有一個可選的<T>,就像min/max, findFirst/Any, 以及reduce的某些形式。這樣做是因為stream中可能沒有任何元素,但是它要提供一個一致的API,既可以處理“一些結果”,也可以處理“沒有結果”。你可以提供默認值,拋異常,或者只在有結果的時候執行一些動作。

它與Guava&rsquo;s Optional類非常非常的相似。它一點都不像是在Scala里的操作,也不會試圖成為之一,有相似的地方純屬巧合。

旁白:Java 8&prime;s Optional和Guava&rsquo;s Optional最終如此的相似是很有趣的事,盡管荒謬的辯論發生在這兩個庫。

“FYI&hellip;. Optional was the cause of possibly the single greatest conflagration on the internal Java libraries discussion lists ever.”

Kevin Bourrillion在 response to “Some new Guava classes targeted for release 10&Prime;如實寫到:

“On a purely practical note, the discussions surrounding Optional have exceeded its design budget by several orders of magnitude.”

Brian Goetz 在  response to “Optional require(s) NonNull”寫到。

StringJoinerandString.join(&hellip;)來得太晚了。他們來得如此之晚以至于大多數Java開發者已經為字符串聯合編寫或發現了有用的工具,但這對JDK本身來說很每秒,因為最終自己實現這一點。每個人都會遇到要求字符串連接的情形,我們現在能夠通過每個Java開發者(事實上的)即將知道的標準的API來闡明,這也算是一件好事。
ComparatorsandComparator.thenComparing(&hellip;)提供了非常優秀的工具,基于鏈的比較和基于域的比較。像這樣:

people.sort(Comparators.comparing(Person::getLastName)                         .thenComparing(Person::getFirstName));

這些新增功能提供了良好的,復雜的各種可讀的簡寫。大多數用例由JDK里增加的 ComparisonChain和Ordering工具類來提供服務。對于什么是有價值的,我認為JDK版本比在Guava-ese里功能等效的版本的可讀性好了很多。

其實,還有很多的小問題的修正和一些性能的改進在這篇文章中沒有提及,但是那些也是非常的重要的。

主要是想全面的介紹到Java 8的每個語言層面和API層面的改進。

看完上述內容,你們掌握Java 8的新特性以及改進有哪些的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

稻城县| 杭锦旗| 随州市| 日照市| 辽中县| 大安市| 綦江县| 宁南县| 巫山县| 铜陵市| 保定市| 城固县| 福建省| 云林县| 金乡县| 海安县| 金川县| 襄汾县| 平江县| 裕民县| 舟山市| 鹤山市| 贵州省| 凯里市| 临夏市| 林芝县| 阿克陶县| 莱阳市| 江华| 阿克苏市| 麟游县| 临夏县| 五华县| 扶绥县| 阳西县| 兴业县| 长治县| 延边| 晋宁县| 九江县| 陕西省|