Java11中的新功能和API詳解系列1

chszs發表於2018-09-27
版權宣告:本文為博主chszs的原創文章,未經博主允許不得轉載。 https://blog.csdn.net/chszs/article/details/82870507

Java 11中的新功能和API詳解系列1

  • 2018.9.27
  • 版權宣告:本文為博主chszs的原創文章,未經博主允許不得轉載。

JDK 11在語言語法方面有一個小改動,增加了相當數量的新API,以及執行單檔案應用程式而無需使用編譯器的能力。此外,可以看到刪除了java.se.ee聚合器模組,這可能會影響將現有應用程式遷移到JDK 11。

JEP-323:Lambda引數的本地變數語法

Java 10中引入了區域性變數型別推斷(JEP-286)。這簡化了程式碼編寫,因為不再需要顯式宣告區域性變數的型別,而是可以使用關鍵字var。JEP-323將此語法的使用擴充套件到Lambda表示式的引數。看下面的例子:

list.stream()
    .map((var s) -> s.toLowerCase())
    .collect(Collectors.toList());

當然,精明的Java程式設計師會指出Lambda表示式已經有型別推斷了,因此在這種情況下使用var會是多餘的。我們可以輕鬆地編寫相同的程式碼:

list.stream()
    .map(s -> s.toLowerCase())
    .collect(Collectors.toList());

那麼為什麼要新增var支援呢?答案是,它針對一種特殊情況,即在想要為Lambda引數新增註釋時的情況。如果沒有涉及型別,那麼無法執行此操作。為了避免使用顯式型別,我們可以使用var來簡化這一點,因此:

list.stream()
    .map((@Notnull var s) -> s.toLowerCase())
    .collect(Collectors.toList());

此特性需要更改Java語言規範(JLS,Java Language Specification),具體如下:

  • 第24頁:var特殊識別符號的描述
  • 第627頁-30:Lambda引數
  • 第636頁:Lambda表示式的執行時評估
  • 第746頁:Lambda語法

JEP-330:啟動單檔案原始碼程式

Java經常面臨的一個批評是它的語法可能很冗長,與執行一個簡單的應用程式相關的“儀式”可能會使初學者感覺難以接近。要編寫一個只列印“Hello World”的應用程式,它需要使用者先編寫一個類,編寫public static void main方法,在方法中使用System.out.println方法。完成此操作後,還必須使用javac編譯原始碼。最後,使用java執行編譯後的位元組碼程式,然後才能看到“Hello World”的輸出。而在當前的大多數指令碼語言中,要列印“Hello World”,操作非常簡單快捷。

JEP-330消除了編譯單個檔案應用程式的需要,因此現在可以直接鍵入:

java HelloWorld.java

Java啟動程式會自動識別HelloWorld.java檔案包含了Java原始碼,並在執行之前將原始碼編譯為位元組碼檔案,省去了編譯這一步驟。

原始檔名後放置的內容,在程式執行時作為引數傳遞。原始檔名前放置的內容,在程式編譯時和執行時作為引數傳遞給Java啟動程式。這允許在命令列上設定類路徑。與編譯器相關的引數(例如類路徑)將傳遞給javac進行編譯。比如:

java -classpath /home/foo/java Hello.java Bonjour

相當於:

javac -classpath /home/foo/java Hello.java
java -classpath /home/foo/java Hello Bonjour

這個JEP還提供了’Shebang’支援。為了減少在命令列上提及Java啟動程式的需要,可以在原始檔的第一行包含如下內容。例如:

#!/usr/bin/java --source 11
    public class HelloWorld {
        ...

注:Shebang也叫Hashbang,在計算領域,它是由井號和感嘆號(#!)開頭的字元序列組成。在類Unix作業系統中,當使用帶有shebang的文字檔案時,就好像它是可執行檔案那樣,程式載入器會將除檔案首行的其餘部分作為直譯器指令進行解析,執行指定的直譯器程式,並將嘗試執行指令碼時最初使用的路徑作為引數傳遞給它,以便程式可以將該檔案用作輸入資料。shebang行通常被直譯器忽略,因為符號“#”是許多指令碼語言中的註釋標記;一些不使用雜湊標記開始的語言直譯器仍然可能會忽略shebang行以識別其目的。

必須使用–-source標識指定要使用的Java版本。

JEP-321:HTTP客戶端(標準)

Java 9引入了一個新的API來提供對HTTP客戶端協議(JEP-110)的支援。由於Java 9引入了Java平臺模組系統(JPMS,Java Platform Module System),因此該API作為孵化器模組包含在內。孵化器模組旨在提供新API,而不使它們成為Java SE標準的一部分。開發人員可以嘗試這些API並提供反饋。一旦進行了任何必要的更改(此API已在JDK 10中更新),就可以移動這些API,使之以成為標準庫的一部分。

HTTP Client API現在是Java SE 11標準庫的一部分。這向JDK引入了一個新的模組和包。此API定義的主要型別有:

  • HttpClient
  • HttpRequest
  • HttpResponse
  • WebSocket

此API可以用於同步或非同步。非同步模式需使用CompletableFutures和CompletionStages。

JEP-320:移除了Java EE和CORBA模組

通過在Java 9中引入JPMS,可以將單片rt.jar檔案拆分為多個模組。JPMS的另一個優點是現在可以建立一個僅包含應用程式所需模組的Java執行時,從而大大減小了程式的尺寸。通過清晰定義的模組邊界,現在可以更輕鬆地刪除過時的Java API部分。這是JEP的作用;java.se.ee元模組包含六個子模組,這些模組不再是Java SE 11標準庫的一部分,不包含在JDK中。受影響的模組有:

  • CORBA
  • corba
  • transaction
  • activation
  • xml.bind
  • xml.ws
  • xml.ws.annotation

自Java 9以來,這些模組已被棄用,預設情況下不包含在編譯或執行時中。如果您嘗試在JDK 9或JDK 10上編譯或執行使用這些模組的API的應用程式,則程式會失敗。如果在程式碼中使用這些模組中的API,則需要將它們作為單獨的模組或庫提供。

新API

Java 11中的許​​多新API都來自HTTP客戶端模組,現在它已成為標準的一部分,以及包含Flight Recorder。

在這裡列出的是除了java.net.http和jdk.jfr模組之外的所有新方法。另外也沒有列出java.security模組中的新方法和類,它們非常特定於JEP-324和JEP-329的更改(有六個新類和八個新方法)。

java.io.ByteArrayOutputStream

  • void writeBytes(byte[]):將引數的所有位元組寫入輸出流

java.io.FileReader

兩個允許指定Charset的新建構函式

java.io.FileWriter

四個允許指定Charset的新建構函式

java.io.InputStream

  • io.InputStream nullInputStream():返回InputStream未讀取任何位元組的內容。當你第一次看這個方法(以及那些OutputStream,Reader,和Writer)時,可以將它們視為/dev/null,以丟棄不需要的輸出或提供始終返回零位元組的輸入。

java.io.OutputStream

  • io.OutputStream nullOutputStream()

java.io.Reader

  • io.Reader nullReader()

java.io.Writer

  • io.Writer nullWriter()

java.lang.Character

  • String toString(int):這是現有方法的過載形式,但採用int而不是char。int是Unicode程式碼點。

java.lang.CharSequence

  • int compare(CharSequence, CharSequence):按CharSequence字典順序比較兩個例項。如果第一個序列按字典順序小於、等於或大於第二個序列,則返回負值、零或正值。

java.lang.ref.Reference

  • lang.Object clone():這個令人很困惑。此Reference類不實現Cloneable介面和此方法將總是丟擲CloneNotSupportedException。必須有一個理由將其包含在內,大概是為了將來的某些東西。

java.lang.Runtime

java.lang.System

這裡沒有新方法,但值得一提的是,該runFinalizersOnExit()方法現已從這兩個類中刪除(這可能是相容性問題)。

java.lang.String

我認為這是JDK 11中新API的亮點之一。這裡有幾個有用的新方法。

  • boolean isBlank():如果字串為空或僅包含空格程式碼點(codepoints),則返回true,否則返回false。
  • Stream lines():返回從此字串中提取的行的流,由行終止符分隔。
  • String repeat(int):返回一個字串,其值是此字串重複計數次數的串聯。
  • String strip():返回一個字串,其值為此字串,刪除了所有首部和尾部的空格。
  • String stripLeading():返回一個字串,其值為此字串,並刪除所有首部空格。
  • String stripTrainling():返回一個字串,其值為此字串,並刪除所有尾部空格。

那麼strip()方法與現有的trim()方法有何不同?答案是兩者之間的空格定義有所不同。

java.lang.StringBuffer

java.lang.StringBuilder

這兩個類都有一個新compareTo()方法,它接受一個StringBuffer/StringBuilder並返回一個int。此方法與CharSequence的compareTo()方法用法相同。

java.lang.Thread

沒有其他方法,但已刪除destroy()方法和stop(Throwable)方法。在stop()不帶引數的方法仍然保留。這可能會出現相容性問題。

java.nio.ByteBuffer

java.nio.CharBuffer

java.nio.DoubleBuffer

java.nio.FloatBuffer

java.nio.LongBuffer

java.nio.ShortBuffer

所有這些類現在都有一個mismatch()方法,用於查詢並返回此緩衝區與給定緩衝區之間第一個不匹配的相對索引。

java.nio.channels.SelectionKey

  • int interestOpsAnd(int):以原子方式將此鍵的興趣集設定為現有興趣集和給定值的按位取交集(“與操作”)
  • int interestOpsOr(int):以原子方式將此鍵的興趣集設定為現有興趣集和給定值的按位取合集(“或操作”)

### java.nio.channels.Selector中

  • int select(java.util.function.Consumer, long):為相應通道準備好進行I/O操作的鍵選擇並執行操作。long引數是超時timeout。
  • int select(java.util.function.Consumer):如上所述,除非沒有超時。
  • int selectNow(java.util.function.Consumer):如上所述,除非是非阻塞。

java.nio.file.Files

  • String readString(Path):將檔案中的所有內容讀入字串,使用UTF-8字符集從位元組解碼為字元。
  • String readString(Path, Charset):如上所述,除了使用指定的字符集Charset從位元組到字元的解碼。
  • Path writeString(Path, CharSequence, java.nio.file.OpenOption[]:將CharSequence寫入檔案。使用UTF-8字符集將字元編碼為位元組。
  • Path writeString(Path, CharSequence, java.nio.file.Charset, OpenOption[]:如上所述,除了Characters使用指定的Charset編碼為位元組。

java.nio.file.Path

  • Path of(String, String[]):通過轉換路徑字串或字串陣列連線時形成的路徑字串,返回一個Path。
  • Path of(net.URI):通過轉換URI返回一個Path。

java.util.Collection

  • Object[] toArray(java.util.function.IntFunction):返回一個包含此集合中所有元素的陣列,使用提供的生成器函式來分配返回的陣列。

java.util.concurrent.PriorityBlockingQueue

java.util.PriorityQueue

  • void forEach(java.util.function.Consumer):對Iterable的每個元素執行給定操作,直到處理完所有元素或操作丟擲異常為止。
  • boolean removeAll(java.util.Collection):刪除也包含在指定集合中的所有此集合的元素(可選操作)。
  • boolean removeIf(java.util.function.Predicate):刪除此集合中滿足給定謂詞的所有元素。
  • boolean retainAll(java.util.Collection):僅保留此集合中包含在指定集合中的元素(可選操作)。

java.util.concurrent.TimeUnit

  • long convert(java.time.Duration):將給定的Duratio持續時間轉換為long型。

java.util.function.Predicate

  • Predicate not(Predicate)。返回謂詞,該謂詞是提供的謂詞的否定。

這個很有趣。例如,可以轉換下面的程式碼:

lines.stream()
    .filter(s -> !s.isBlank())

轉換為:

lines.stream()
    .filter(Predicate.not(String::isBlank))

而且,如果我們使用靜態匯入,還可以轉變為:

lines.stream()
    .filter(not(String::isBlank))

這樣的程式碼更簡潔,更容易理解。

java.util.Optional

java.util.OptionalInt

java.util.OptionalDouble

java.util.OptionalLong

  • boolean isEmpty():如果某個值不存在,則返回true,否則返回false。

java.util.regex.Pattern

  • Predicate asMatchPredicate():它建立一個謂詞,測試此模式是否與給定的輸入字串匹配。

java.util.zip.Deflater

  • int deflate(ByteBuffer):壓縮輸入資料並使用壓縮資料填充指定的緩衝區。
  • int deflate(ByteBuffer, int):壓縮輸入資料並使用壓縮資料填充指定的緩衝區。返回壓縮的實際資料位元組數。
  • void setDictionary(ByteBuffer):將壓縮的預設字典設定為給定緩衝區中的位元組。這是現有方法的過載形式,現在可以接受ByteBuffer而不是位元組陣列。
  • void setInput(ByteBuffer):設定壓縮的輸入資料。也是現有方法的過載形式。

java.util.zip.Inflater

  • int inflate(ByteBuffer):將位元組解壓縮到指定的緩衝區中。返回未壓縮的實際位元組數。
  • void setDictionary(ByteBuffer):將預設字典設定為給定緩衝區中的位元組。現有方法的過載形式。
  • void setInput(ByteBuffer):設定解壓縮的輸入資料。現有方法的過載形式。

javax.print.attribute.standard.DialogOwner

這是JDK 11中的一個新類,它是一個屬性類,用於支援請求列印或頁面設定對話方塊保持顯示在所有視窗或某個特定視窗的頂部。

javax.swing.DefaultComboBoxModel

javax.swing.DefaultListModel

  • void addAll(Collection):新增集合中存在的所有元素。
  • void addAll(int, Collection):從指定的索引開始新增集合中存在的所有元素。

javax.swing.ListSelectionModel

  • int[] getSelectedIndices():按遞增順序返回選擇模型中所有選定索引的陣列。
  • int getSelectedItemsCount():返回所選專案的數量。

jdk.jshell.EvalException

  • jshell.JShellException getCause():返回在執行客戶端中由EvalException表示的throwable包裝的原因cause,如果原因不存在(non-existent)或未知(unknown),則返回null。


相關文章