2022/09/20

JEPでは語れないJava 19

このエントリーをはてなブックマークに追加

半年ぶりのJavaのアップデートで、Java 19がリリースされます。

Java 19はJava 18よりJEPは少なく、しかもPreviewやIncubatorでないJEPはJEP 422のLinux/RISC-V Portしかありません。こんなアップデートは初めてかも。

  • 405: Record Patterns (Preview)
  • 422: Linux/RISC-V Port
  • 424: Foreign Function & Memory API (Preview)
  • 425: Virtual Threads (Preview)
  • 426: Vector API (Fouth Incubator)
  • 427: Pattern Matchning for switch (Third Preview)
  • 428: Structured Concurrency (Incubator)

JEP 424のForeign Function & Memory APIは、Java 18まではIncubatorだったのですが、なぜかPreviewに変更されました。今までのFFM APIはjdk.incubator.foreignモジュールから、java.baseモジュールに変更されて、パッケージがjava.lang.foreignになったからなのかもしれません。

なお、Java 19からはFFMに関連して、Restricted MethodsがSpecificationに記述されるようになりました。Javaが管理していないメモリへのアクセスするAPIなどがRestricted Methodsに指定されています。

JEP 426 Vector APIはなかなかIncubatorが外れずにFouthまで行ってしまいました。なかなか難しいですね。

JEP 427 Pattern Matching for switchもThird Previewです。JEP 405 Record Patternsはinstance ofでRecordのプロパティを直接扱えるようになる機能です。これもinstance ofの後はswitchでも使えるようになるはずなので、Pattern Matching for switchが正式になるのはいつになるのか...

JEP 425 Virtual ThreadsはProject Loomで策定されているAPIで、当初はFiberと呼ばれていたものです。Virtual Threadsが銀の弾丸のように書いてある記事もありますけど、実際はそんなことは全然ないんですけどね。ちゃんと設計されたマルチスレッドのシステムであれば、Virtual Threadsを使わなければならない場面は少ないはずです。

JEP 428 Structed Concurrencyは複数のタスクを例外も含めて扱いやすくするためにStructuredTaskScopeクラスを導入するJEPです。

 

ということで、PreviewやIncubatorがついていないStandard JEPの新機能というのは、Java 19ではないことになってます。しかし、JEPに記述されていないAPIの追加は意外に多いんですよね。

 

今回はjava.baseモジュールなどにPreview JEPのAPIが多く導入されていますが、JEPでの新機能は他にゆずって、ここではPreviewやIncubatorのAPIの説明は省略します。また、java.baseモジュール以外のモジュールの変更は少ないし、普通の開発ではほぼ使われないAPIなので、今回はjava.baseモジュールだけ説明します。例によってセキュリティ系のAPIの変更は櫻庭がよく理解していないので省略します。

 

廃止になったAPI

Java 19では、なんと廃止になったAPIはありません。これも珍しいですね。

 

廃止予定のAPI

Java 19で追加された廃止予定のAPIは、SwingのPluggable Look-and-Feel関連のクラスとメソッドです。

 

クラス

前述したようにSwingのPluggable Look-and-Feel関連のクラスがforRemoval=trueになりました。

  • javax.swing.plaf.basic.BasicMenuItemUI.MouseInputHandler
  • javax.swing.plaf.basic.BasicScrollPaneUI.HSBChangeListener
  • javax.swing.plaf.basic.BasicScrollPaneUI.PropertyChangeHandler
  • javax.swing.plaf.basic.BasicScrollPaneUI.ViewportChangeHandler
  • javax.swing.plaf.basic.BasicScrollPaneUI.VSBChangeListener

 

メソッド

メソッドもSwingのPluggable Look-and-Feel関連です。

  • javax.swing.plaf.basic.BasicDirectoryModel.intervalAdded
  • javax.swing.plaf.basic.BasicDirectoryModel.intervalRemoved
  • javax.swing.plaf.basic.BasicDirectoryModel.lt
  • javax.swing.plaf.basic.BasicToolBarUI.createFloatingFrame

 

追加されたAPI

Java 19で追加されたAPIはかなり多いのですが、半分以上はFFM APIです。とはいうものの、FFM以外でもかなり多くのAPIが追加されています。

 

java.base/java.ioパッケージ

java.ioパッケージではシリアライゼーション関連の例外のコンストラクタが追加されました。なぜ、今、これらのコンストラクタが追加されたのかはよく分かりません。

 

InvalidClassException例外

例外の原因を示すcauseがコンストラクタ引数で指定できるようになりました。

  • InvalidClassException(String reason, Throwable cause)
  • InvalidClassException(String cname, String reason, Throwable cause)

 

InvalidObjectException例外

こちらも同じく、例外の原因を示すcauseがコンストラクタ引数で指定できるようになりました。

  • InvalidObjectException(String reason, Throwable cause)

 

ObjectStreamException例外

こちらも同じです。

  • ObjectStreamException(String message, Throwable cause)
  • ObjectStreamException(Throwable cause)

 

java.base/java.langパッケージ

java.langパッケージも多くのAPIが追加されていますが、Virtual Thread関連のものが多いため、それ以外のAPI変更を説明します。

 

Character.UnicodeBlockクラス

Java 19ではUnicode 14.0をサポートするようになりました。

Unicode 14.0というと敬礼の絵文字などが使えるようになっています。しかし、それ以外にも古代アルバニア文字やインドなどで使われているらしいTangsa語の文字などが追加されています。そのためにBlockとScriptも追加されています。

  • ARABIC_EXTENDED_B
  • CYPRO_MINOAN
  • ETHIOPIC_EXTENDED_B
  • KANA_EXTENDED_B
  • LATIN_EXTENDED_F
  • LATIN_EXTENDED_G
  • OLD_UYGHUR
  • TANGSA
  • TOTO
  • UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS_EXTENDED_A
  • VITHKUQI
  • ZNAMENNY_MUSICAL_NOTATION

 

Character.UnicodeScriptクラス

こちらも同じく、Unicode 14.0で追加されたScriptが追加されています。

  • CYPRO_MINOAN
  • OLD_UYGHUR
  • TANGSA
  • TOTO
  • VITHKUQI

 

note: 以下の説明はJava 19ではなくて、Java 20の機能でした。Satoさん、ご指摘ありがとうございます。

APIの変更ではないのですが、java.text.BreakIteratorクラスの実装が拡張されて結合文字の絵文字に対応できるようになっています。

今までは正規表現の\b{g}で分解するしかなかったのですが、BreakIteratorクラスのgetChracterInstanceメソッドでできるようになったようです。詳しくはJBSのJDK-8291660をご覧ください。

   - ここまで -

 

Doubleクラス

定数が1つ追加されていますが、これはJLS 4.2.3で定義されている浮動小数点のNを表すものです。

  • PRECISION

PRECISIONはintで定義されていて、doubleでは53になっています。

 

Floatクラス

FloatクラスもDoubleクラスと同じく、JLS 4.2.3で定義されている浮動小数点のNを表す定数が追加されました。

  • PRECISION

floatでは24に定義されています。

 

Integerクラス/Longクラス

まさかIntegerクラスにメソッドが追加されるとは思いもよりませんでした。

  • static int compress(int i, int mask)
  • static int expand(int i, int mask)

Longクラスの場合は引数と戻り値の型がlongになります。

compressはmaskのビットが立った桁のみを残して、取り除いた桁は詰めて表現した数にします。Javadocにある例は

jshell> int compress = Integer.compress(0xCAFEBABE, 0xFF00FFF0)
compress ==> 830379

jshell> System.out.printf("%X%n", compress)
CABAB

maskがFF00FFF0 (1111 1111 0000 0000 1111 1111 1111 0000)なので、16進のCAFEBABEの1になっているビット桁だけにすると CA は残って FE は削除、BAB が残って E が削除。残った部分をくっつけると CABAB となるわけです。

expandメソッドは逆にマスクのビットが立っている桁に、ビットを置きなおす感じです。

jshell> int ex = Integer.express(0xCABAB, 0xFF00FFF0)
ex ==> 211860144

jshell> System.out.printf("%X%n", ex)
CA00BAB0

この演算は下位ビットから当てはめていくので、ビットの立っている箇所だけではiが表されない場合、上位ビットが省略されてしまうようです。

jshell> int ex = Integer.express(0xCABAB, 0x0000FFF0)
ex ==> 47792

jshell> System.out.printf("%X%n", ex)
BAB0

 

Mathクラス/StrictMathクラス

定数にτが追加されました。

  • static final double TAU

τは円の半径に対する円周長の比になり、値としては2πになります。

jshell> Math.TAU
$1 ==> 6.2831853071795

 

Threadクラス

ThreadクラスにはVirtual Thread関連のAPIが増えていますが、それ以外にもいくつかメソッドが追加されました。

  • boolean join(Duration duration)
  • void sleep(Duration duration)
  • long threadId()

joinメソッドとsleepメソッドはタイムアウトをミリ秒で設定できましたが、Java 19で任意の単位の時間で指定できるようなオーバーロードが追加されました。

threadIdメソッドはスレッドのIDを取得するためのメソッドです。

 

java.base/java.mathパッケージ

BigDecimalクラスに定数が追加されました。

 

BigDecimalクラス

2を表す定数が追加されています。

  • BigDecimal TWO

 

BigIntegerクラス

パラレルに乗算を行うメソッドが追加されています。

  • BigInteger parallelMultiply(BigInteger val)

this×valを行う演算ですが、数値が千を超えるようなビット数の場合、処理をパラレルで行います。

 

java.base/java.textパッケージ

DecimalFormatSymbolsクラスにメソッドが追加されました。

 

DecimalFormatSymbolsクラス

ロケールを返すメソッドが追加されています。

  • Locale getLocale()
jshell> var symbols = DecimalFormatSymbols.getInstance()
symbols ==> java.text.DecimalFormatSymbols@f6cadb1e

jshell> symbols.getLocale()
$1 ==> ja_JP

 

java.base/java.time.chronoパッケージ

ISO 8601準拠かどうかを返すメソッドが追加されました。

 

Chronologyインタフェース

暦がISO 8601に準拠しているかどうかを返すメソッドが追加されました。

  • defualt boolean isIsoBased()

デフォルトではfalseを返しますが、ISOChronologyクラスなどはtrueを返します。JapaneseChronologyクラスなどもtrueを返します。ただし、太陰暦であるヒジュラ暦を表すHijrahChronologyクラスはfalseを返します。

 

java.base/java.time.formatパッケージ

ロケール指定に関してのメソッドが追加されています。

 

DateTimeFormatterクラス

ローカライズしたパターンの生成を行うメソッドが追加されました。

  • DateTimeFormatter ofLocalizedPattern(String requestedTemplate)

今までofPatternメソッドでロケールを渡すことで同じようなことができましたが、このメソッドはISO 8601準拠の暦をしようすることが前提となっているようです。引数のrequestedTemplateには通常のDateTimeFormatterのフォーマットとは異なり、正規表現で記述するようになっています。使用できる正規表現はJavadocに記載されています。

また、ResolverStyleがSMARTになります。

 

DateTimeFormatterBuilderクラス

こちらも、ロケールに応じたビルダー生成のメソッドが追加されました。

  • DateTimeFormatterBuilder appendLocalized(String requestedTemplate)
  • String getLocalizedDateTimePattern(String requestedTemplate, Chronology chrono, Locale locale)

appendLocalizedメソッドは、DateTimeFormatter.ofLocalizedPatterメソッドのために作られたメソッドのようです。ofLocalizedPatterメソッドの実装で使われていました。

getLocalizedDateTimePatternメソッドはofLocalizedPatternメソッドで指定した正規表現のrequestedTemplateから通常のDateTimeFormatterクラスで使われるパターンを取得するためのメソッドのようです。

 

java.base/java.utilパッケージ

 

HashMapクラス, LinkedHashMapクラス, WeakHashMapクラス, HashSetクラス, LinkedHashSetクラス

マップオブジェクトを生成するためのファクトリメソッドが追加されています。

  • <K, V> HashMap<K, V> newHashMap(int numMappings)

上のnewHashMapメソッドはHashMapクラスで定義されたメソッドです。LinkedHashMapクラスはnewLinkedHashMapメソッド、WeakHashMapクラスはnewWeakHashMapメソッドになります。

同様に、HashSetクラスはnewHashSetメソッド、LinkedHashSetクラスはnewLinkedHashSetメソッドになります。

これらのメソッドはいずれも空のミュータブルなマップオブジェクトを生成します。マップオブジェクトの初期容量は、引数のnumMappingsが負荷係数0.75になるように設定されます。

 

Localeクラス

3種類のファクトリメソッドが追加されています。

  • static Locale of(String language)
  • static Locale of(String language, String country)
  • static Locale of(String language, String country, String variant)

最近のJavaではファクトリメソッドにofが使われるようになっているので、Localeクラスもそれにならったようです。ofメソッドを使う方がキャッシュを使用するので、不要なオブジェクト生成を抑制できます。今後はnewでオブジェクト生成をするのではなく、ofメソッドを使うべきです。

 

Objectsクラス

どこかで見たことのあるはずな表記を作るためのメソッドが追加されました。

  • static String toIdentityString(Object o)

このメソッドを使うと、 型名@ハッシュコード 形式の文字列を作ってくれます。

jshell> var text = "ABC"
text ==> "ABC"

jshell> Objects.toIdentityString(text)
$2 ==> "java.lang.String@b1a58a3"

この形式、Java使っていたら見たことあるはずですよね。toStringメソッドのデフォルトがこの形式の文字列を返します。まぁ、だいたいのクラスはtoStringメソッドをオーバーライドしてしまいますけど。

 

Randomクラス

ファクトリメソッドが1つ追加されました。

  • static Random from(RandomGenerator generator)

RandomGeneratorインタフェースはJava 17で追加されたインターフェースです。RandomクラスはRandomGeneratorインタフェースを実装していますが、乱数生成器を指定することはできませんでした。fromメソッドを使用すると任意の乱数生成器を指定して、Randomオブジェクトを生成することができます。

 

java.base/java.util.concurrentパッケージ

java.util.concurrentパッケージもいろいろと追加されていますが、JEP 425関連のメソッドも多いです。

 

ExecutorServiceインタフェース

やっと、ExecutorServiceインタフェースがAutoClosableになりました!!

  • default void close()

AutoClosableインタフェースを実装しているということは、try-with-resources構文で記述できるようになるということです。今まで使い終わった後にshutdownメソッドをコールしなくてはいけなかったのが、解放されました。

デフォルト実装ではshutdownメソッドをコールして、awaitTerminationメソッドで終わるまで待つ実装になっています。

 

ForkJoinPoolクラス

ForkJoinPoolクラスはExecutorServiceインタフェースを実装しているので、こちらもAutoClosableになっています。それ以外に2つのメソッドが追加されました。

  • default void close()
  • <T> ForkJoinTask<T> lazySubmit(ForkJoinTask<T> task)
  • int setParallelism(int size)

lazySubmitメソッドは、名前の通りsubmitメソッドのlazy版です。最終的には実行されますが、いつ実行されるかはスレッドの空き状況によります。

ForkJoinPoolクラスは生成時に並行度を指定できますが、setParallelismメソッドを使うと後から変更することができます。

 

ForkJoinTaskクラス

ForkJoinTaskクラスには3つのメソッドが追加されました。

  • static <T> ForkJoinTask<T> adaptInterruptible(Callable<? extends T> callable)
  • boolean quietlyJoin(long timeout, TimeUnit unit)
  • boolean quietlyJoinUninterruptibly(long timeout, TimeUnit unit)

adaptInterruptatibleメソッドはadaptメソッドの割り込み可能版です。タスクをcancelメソッドでキャンセルするときに、cancelメソッドの引数のmayInterruptIfRunningをtrueにしておくと、割り込みをかけてキャンセルしてくれます。

quietlyJoinメソッドのオーバーロードはタイムアウトを指定できるようになりました。引数無しのquietlyJoinメソッドは例外をスローしませんが、タイムアウトを指定できるようになったのでInterruptedException例外がスローされる可能性があります。

もう1つのquietlyJoinUninterruptiblyメソッドはquietlyJoinをする時に割り込みをかけないメソッドです。

 

ForkJoinWorkThreadクラス

ForkJoinWorkThreadクラスはFork/Join Frameworで使用するスレッドです。コンストラクタが1つ追加されました。

  • ForkJoinWorkerThread(ThreadGroup group, ForkJoinPool pool, boolean preserveThreadLocals)

今まで提供されていたコンストラクタはForkJoinPoolオブジェクトだけを指定するものでしたが、ThreadGroupとThreadLocalの有無を指定できるようになっています。このコンストラクタはVirtual Threadに関連してそうなんですけど、Previewではないようです。

 

Future.State列挙型

Futureインタフェースに状態を示す列挙型が追加されました。

定数として、以下の4種類が定義されています。

  • CANCELLED
  • FAILED
  • RUNNING
  • SUCCESS

というか、State列挙型のようなものが今までなかったのが不思議だったんですよね。

 

Futureインタフェース

Future.State列挙型の導入に伴い、それを使うメソッドが追加されました。

  • default Throwable exceptionNow()
  • default V resultNow()
  • default Future.State state()

stateメソッドは現在の状態を表すメソッドです。戻り値の方はもちろんFuture.State列挙型です。

resultNowメソッドは結果を取得するメソッドなのですが、getメソッドとは異なって、結果取得を待たないです。つまり、正しい値を取得するには状態がSUCCESSの場合だけです。

デフォルト実装では、その他の状態の場合、IllegalStateException例外がスローされるようになっています。

exceptionNowメソッドも同様に例外の取得を待たないメソッドです。今ままではgetメソッドのExecutionException例外のcauseで原因となる例外を取得していましたが、状態がFAILの場合はexceptionNowメソッドで例外を取得できるようになっています。

デフォルト実装では、その他の状態の場合、同じようにIllegalStateException例外がスローされます。

 

java.base/java.util.spiパッケージ

ToolProviderクラスにメソッドが追加されました。

 

ToolProviderクラス

ToolProviderクラスはServiceLoaderクラスによって呼び出されるクラスなので、普通は使わないとは思いますが...

  • Optional<String> description()

ToolProviderオブジェクトの説明があれば返します。デフォルト実装ではOptional.empty()を返していました。

一応、jar, javac, jlinkの場合の説明がJavadocに記載されているので、興味があれば見てみてください。

 

 

というわけで、Java 19のJEPにのっていないAPIの変更でした。Java 19ではFFM APIやVirtual ThreadsなどのPreviewのAPI変更が多いのですが、意外にもそうでないAPIの変更も多めでした。個人的にはFuture.State列挙型の導入がうれしいですね。

PreviewやIncubatorもいつか紹介したいとは思ってはいます。