2022/03/22

JEPでは語れないJava 18

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

半年ぶりのJavaのアップデートの時間です。

Java 18はLTSの次のバージョンということもあり、JEPは少なめです。

  • 400: UTF-8 by Default
  • 408: Simple Web Server
  • 413: Code Snippets in Java API Documentation
  • 416: Reimplement Core Reflection with Method Handles
  • 417: Vector API (Third Incubator)
  • 418: Internet-Address Resolution SPI
  • 419: Foreign Function & Memory API (Second Incubator)
  • 420: Pattern Matching for switch (Second Preview)
  • 421: Deprecate Finalization for Removal

しかし、日本、特にWindowsの日本語環境で運用しているシステムにとって、とても重大な変更があります。

それが、JEP 400のUTF-8 by Defaultです。

Reader/Writer系のクラスで文字コードを指定しない場合、デフォルトの文字コードとしてUTF-8が使われるようになります。今まで、Windowsの日本語環境ではデフォルトの文字コードはWindows-31j (MS932)だったので、それを前提とした入出力は動作がおかしくなります。

もちろん、互換性維持のための策もちゃんとあって、file.encodingプロパティをCOMPAT、つまり実行時にオプションとして-Dfile.encoding=COMPATを指定すれば今まで通りのデフォルトの文字コードになります。

しかし、デフォルトの文字コードに依存したコードはなるべく早いうちに、文字コードを指定するコードに書き換えるべきです。

なお、NIO.2を使用した入出力はすでにデフォルトの文字コードがUTF-8になっているので、変更は必要ありません。

 

JEP 408は以前よりJDKに含まれていたWeb Server機能を使用できるツールの提供、JEP 413はJavadocにコードを書くために@snippetタグの導入です。

JEP 416はリフレクションの実装方法の改善です。JEP 421は以前より予告されていたfinalizerの廃止です。for Removalになったので、どんなに遅くなったとしても次のLTSではfinalizeメソッドは使えないと思った方がいいです。

他のIncubatorモジュールやPreviewは2ndや3rdなので、もうおなじみ?

 

例によってセキュリティ系のAPIの変更は櫻庭がよく理解していないので、省略します。

 

廃止になったAPI

メソッド

JEP 421関連でfinalizeメソッドが廃止になりました。これらはJava 16でfor Removalになっていたものです。

  • java.awt.color.ICC_Profile.finalize()
  • java.awt.image.ColorModel.finalize()
  • java.awt.image.IndexColorModel.finalize()

いずれもAWT関連なので、特に問題にはならないと思います。

 

廃止予定のAPI

Java 18で追加された廃止予定のAPIは、JEP 421関連のfinalizeメソッドがほとんどだけです。

 

メソッド

JEP 421関連のfinalizeメソッド以外のメソッドとして、とうとうThread.stop()メソッドがforRemovalになりました。stopメソッドを使われていることも少なくなっているとは思いますが、注意が必要です。

また、セキュリティ系の情報を保持するSubjectクラスのdoAsメソッドが廃止予定になりました。

  • java.awt.Graphics.finalize()
  • java.awt.PrintJob.finalize()
  • java.lang.Enum.finalize()
  • java.lang.Object.finalize()
  • java.lang.Runtime.runFinalization()
  • java.lang.System.runFinalization()
  • java.lang.Thread.stop()
  • java.util.concurrent.ThreadPoolExecutor.finalize()
  • javax.imageio.spi.ServiceRegistry.finalize()
  • javax.imageio.stream.FileCacheImageInputStream.finalize()
  • javax.imageio.stream.FileImageInputStream.finalize()
  • javax.imageio.stream.FileImageOutputStream.finalize()
  • javax.imageio.stream.ImageInputStreamImpl.finalize()
  • javax.imageio.stream.MemoryCacheImageInputStream.finalize()
  • javax.security.auth.Subject.doAs(Subject,PrivilegedAction)
  • javax.security.auth.Subject.doAs(Subject,PrivilegedExceptionAction)

 

追加されたAPI

LTSの次のバージョンということもあり、Java 18のAPIの追加はあまりありません。ただし、java.baseモジュールにメソッド追加が多いです。

 

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

java.ioパッケージでは2つのメソッドが追加されましたが、1つはスーパークラスで定義されていたものをオーバライドしたメソッドです。それがFileInputStreamクラスのtransferToメソッドです。

もう1つのメソッドがJEP 400に関連したメソッドです。

 

PrintStreamクラス

PrintSreamクラスでは現在使用している文字セットを返すcharsetメソッドが追加されました。

  • Charset charset()

Java 17でCosoleクラスにcharsetメソッドが追加されましたが、同じようにファイルに出力を行う文字セットを返します。

 

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

java.langパッケージではMathクラスとStrictMathクラスにメソッドが追加されました。いずれも同じメソッドなので、一緒に説明します。

Mathクラス/StrictMathクラス

Math/StrictMathクラスでは、それぞれ13のメソッドが追加されました。

  • int ceilDiv(int x, int y)
  • long ceilDiv(long x, int y)
  • long ceilDiv(long x, long y)
  • int ceilDivExact(int x, int y)
  • long ceilDivExact(long x, long y)
  • int ceilMod(int x, int y)
  • int ceilMod(long x, int y)
  • long ceilMod(long x, long y)
  • int divideExact(int x, int y)
  • long divideExact(long x, long y)
  • int floorDivExact(int x, int y)
  • long floorDivExact(long x, long y)
  • long unsignedMultiplyHigh(long x, long y)

Exactがつくメソッドは、ArithmeticException例外を投げるという違いだけなので、それ以外のメソッドを説明します。

ceilDiv系のメソッドは演算結果より大きいもしくは同じになる最小の整数を返します。

jshell> Math.ceilDiv(10,3)
$1 ==> 4

jshell> Math.ceilDiv(9, 3)
$2 ==> 3

jshell> Math.ceilDiv(-10, 3)
$3 ==> -3

ceilMod系の割り算の余りなのですが、負の値になることもあります。つまり、z = Math.ceil(x, y)だったときに、ceilModメソッドの返り値はx - z * yになります。

jshell> Math.ceilMod(10,3)
$1 ==> -2

jshell> Math.ceilMod(9, 3)
$2 ==> 0

jshell> Math.ceilMod(-10, 3)
$3 ==> -1

unsignedMultiplyHighメソッドはmultiplyHighメソッドの符号なし版です。

 

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

JEP 418でインターネットアドレスの名前解決がSPI化され、それに応じて4つのインタフェース/クラスが追加されました。

  • InetAddressResolverインタフェース
  • InetAddressResolver.LookupPolicyクラス
  • InetAddressResolverProviderインタフェース
  • InetAddressResolverProvider.Configurationクラス

これで独自の名前解決クラスを実装することができるようになります。

 

java.base/java.nio.charsetパッケージ

Charsetクラスにメソッドが1つ追加されています。

Charsetクラス

指定された文字セットを返すforNameメソッドがオーバーロードされました。

  • Charset forName(String charsetName, Charset fallback)

今までのforNameメソッドは指定された文字セットがない場合、IllegalCharsetNameException例外を投げます。これに対し、Java 18で追加されたforNameメソッドは文字セットがない場合、第2引数のfallbackが戻ります。

今までは文字セットがなかった場合は例外処理で処理しなくてはならなかったのが、fallbackを指定できるのでコードが分かりやすくなるはずです。

 

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

Durationクラスにメソッドが1つ追加されています。

Durationクラス

Durationクラスは時間間隔表すクラスですが、保持している時間間隔が正の値なのか調べるためのメソッドが追加されました。

  • boolean isPositive()

isZeroメソッドと、isNegativeメソッドはあったので、これで3つ揃いました。

 

java.net.http/java.net.httpパッケージ

HTTPリクエストを作成するBuilderクラスにメソッドが1つ追加されています。

HttpRequest.Builderクラス

HTTPリクエストを作成するBuilderクラスは、これまでHTTPメソッドのGET, POST, PUT, DELETEを作成するメソッドはあったのですが、HEADを作成するメソッドはありませんでした(HEADメソッドのリクエストを作ることはできます)。そこで、HEADメソッドが追加されています。

  • HttpRequest.Builder HEAD()

これまで、HEADメソッドはmethodメソッドで作らなくてはならなかったのが、少し簡単になりました。

 

java.xml/javax.xml.xpathパッケージ

なぜ、この時期にXPathにメソッドが追加されたのか全然わからないのですが、XPathのファクトリにメソッドが2つ追加されました。

XPathFactoryクラス

XPathFactoryクラスで属性を設定、取得するメソッドが追加されました。

  • String getProperty(String name)
  • void setProperty(String name, String value)

追加されたのはいいのですが、使い道がよく分かりません。デフォルトの実装ではUnsupportedOperationException例外が投げられるようになっています。

 

java.compilerモジュール

毎度のことですが、java.compilerモジュールはいろいろと追加されています。いつものソースバージョンやらなにやらが大半ですが、アノテーション処理関連でも少しだけメソッドが追加されています。とはいうものの、普通は使わないので省略します。

 

ということで、Java 18のAPIの変更をまとめました。

LTSの次のバージョンということで、変更点は少なめですね。