2019/10/04

Java SE 13: Unmentioned in JEPs

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

Java SE 13 was released on 17th Sep.

In that day, Oracle Code One was held in San Francisco, and Brian Goetz talked about new features of Java SE 13 in Code One keynote.

However, new features of Java 13 are a little. Only 5 JEPs are introduced in Java SE. There are no JEP about library.

2 JEPs are about language specification: one is switch expression (JEP 354) and other is text block (JEP 355).

switch expression was introduced as preview feature in Java 12. It was discussed again, and was re-proposed in Java 13.

Text block is originally JEP 326 Raw String Literal. Text block is also preview feature.

 

In this entry, I'll explain new features, mainly API updates. These are unmentioned in JEPs.

But, I have enough knowledge about security APIs, so I'll skip these updates.

 

Removed APIs

2 methods were removed in Java SE 13.

These are the methods that forRemoval of @Deprecated set true from Java SE 9.

  • java.lang.Runtime.traceInstructions(boolean)
  • java.lang.Runtime.traceMethodCalls(boolean)

As you can see in these methods Javadoc, descriptions of the methods are "Not implemented, does nothing." I don't know why the methods didn't removed until Java 13.

 

APIs Proposed for Removal

Many APIs are poposed for removal in Java 13. I listed APIs that forRemoval of @Deprecated were true.

Package

  • javax.security.cert

Classes

  • javax.security.cert.Certificate
  • javax.security.cert.X509Certificate

Exceptions

  • javax.security.cert.CertificateEncodingException
  • javax.security.cert.CertificateException
  • javax.security.cert.CertificateExpiredException
  • javax.security.cert.CertificateNotYetValidException
  • javax.security.cert.CertificateParsingException

Methods

  • java.lang.String.formatted
  • java.lang.String.stripIndent
  • java.lang.String.translateEscapes
  • javax.net.ssl.HandshakeCompletedEvent.getPeerCertificateChain
  • javax.net.ssl.SSLSession.getPeerCertificateChain

With removal of javax.security.cert package, we should use java.security.cert package instead of javax.security.cert package.

3 methods of String class are new methods in Java 13. However, forRemoval variables are true. Why?

The answer is that these methods are associated with text bloch feature. Because text bloch is preview feature, these methods may be changed when text bloch becames official feature.

3 methods of String class are explained after.

2 methods of javax.net.ssl package are also associated with javax.security.cert package. Return type of HandshakeCompletedEvent.getPeerCertificateChain method is array of X509Certificate class. Insted of getPeerCertificateChain method, we can use getPeerCertificates method that return type is array of Certificate class.

In the same way, we can use SSLSession.getPeerCertificates method instead of getPeerCertificateChain method.

 

New APIs

java.lang package

Java SE 13 supports Unicode 12.1, but the feature is not defined by JEP. In relation to Unicode 12.1 support, some constants are added to 2 classes.

Unicode version supported in Java SE is described in javadoc of java.lang.Character class.

Here is the Character class javadoc of Java SE 13: "Character information is based on the Unicode Standard, version 12.1"

 

Character.UnicodeBlock class

As the name suggests, UnicodeBlock class defines Unicode blocks. UnicodeBlock class adds 9 constants introduced in Unicode 12.0.

  • EGYPTIAN_HIEROGLYPH_FORMAT_CONTROLS
  • ELYMAIC
  • NANDINAGARI
  • NYIAKENG_PUACHUE_HMONG
  • OTTOMAN_SIYAQ_NUMBERS
  • SMALL_KANA_EXTENSION
  • SYMBOLS_AND_PICTOGRAPHS_EXTENDED_A
  • TAMIL_SUPPLEMENT
  • WANCHO

Character.UnicodeScript enum

UnicodeScript enum also defines 4 scripts introduced in Unicode 12.0.

  • ELYMAIC
  • NANDINAGARI
  • NYIAKENG_PUACHUE_HMONG
  • WANCHO

 

String class

As mentioned before, String class defines 3 new methods associated with text block. We can use the methods, but javac compiler alerts for using them.

  • String formatted(java.lang.Object... args)
  • String stripIndent()
  • String translateEscapes()

format method of String class is a static method introduced in J2SE 5, while on the other hand formatted method is a instance method.

jshell>  import java.time.*

jshell> "%s%n".formatted(LocalDate.now())
|  Warning:
|  formatted(java.lang.Object...) in java.lang.String has been deprecated and marked for removal
|  "%s%n".formatted(LocalDate.now())
|  ^--------------^
$1 ==> "2019-09-17\r\n"

jshell>

Both format method and formatted method call format method of java.util.Formatter class internally.

stripIndent method removes line head white-spaces, when text is multi line and meaningless line head white-space.

jshell> var text = "  abc\n" +
   ...> "   def\n" +
   ...> "    ghi"
text ==> "  abc\n   def\n    ghi"

jshell> System.out.println(text)
  abc
   def
    ghi

jshell> System.out.println(text.stripIndent())
abc
 def
  ghi
|  Warning:
|  stripIndent() in java.lang.String has been deprecated and marked for removal
|  System.out.println(text.stripIndent())
|                     ^--------------^

jshell>

When you use text bloch, line head white-spaces are removed automatically.

translateEscapes translate escape sequence into Unicode. For example, "\n" consisting of 2 character is translated into U+000A.

We don't use this method usually, and text block feature uses stripIndent and translateEscape methods.

 

java.nio package

Classes associated with Buffer class are added some methods.

 

Buffer class

Buffer class defined overloaded slice method.

  • Buffer slice(int index, int length)

Existing slice method has no argument, and cuts buffer from current position to limit.

New slice method cut by index and length argument explicitly.

I used both methods with JShell as below:

jshell> var buffer = ByteBuffer.allocate(5)
buffer ==> java.nio.HeapByteBuffer[pos=0 lim=5 cap=5]

jshell> buffer.position(2)
$3 ==> java.nio.HeapByteBuffer[pos=2 lim=5 cap=5]

jshell> var buffer2 = buffer.slice()
buffer2 ==> java.nio.HeapByteBuffer[pos=0 lim=3 cap=3]

jshell> var buffer3 = buffer.slice(2, 3)
buffer3 ==> java.nio.HeapByteBuffer[pos=0 lim=3 cap=3]

jshell>

I used ByteBuffer class because Buffer class is abstract class. We can also use new slice method of other concrete classes such as CharBuffer class.

 

ByteBuffer/CharBuffer/DoubleBuffer/FloatBuffer/IntBuffer/LongBuffer/ShortBuffer class

Each class is added new overloaded get methods put methods.

I explaine the case of ByteBuffer class, but usage is all same.

  • ByteBuffer get(int index, byte[] dst)
  • ByteBuffer get(int index, byte[] dst, int offset, int length)
  • ByteBuffer put(int index, byte[] src)
  • ByteBuffer put(int index, byte[] src, int offset, int length)

Existing get methods reads bytes from current position, or reads 1 byte from specified index. New overloaded get methods read bytres into byte array from specified index.

jshell> var b = new byte[]{0, 1, 2, 3, 4, 5}
b ==> byte[6] { 0, 1, 2, 3, 4, 5 }

jshell> var buffer = ByteBuffer.wrap(b)
buffer ==> java.nio.HeapByteBuffer[pos=0 lim=6 cap=6]

jshell> var bytes = new byte[2]
bytes ==> byte[2] { 0, 0 }

jshell> buffer.get(2, bytes)
$13 ==> java.nio.HeapByteBuffer[pos=0 lim=6 cap=6]

jshell> bytes
bytes ==> byte[2] { 2, 3 }

jshell>

Above code reads two bytes from ByteBuffer object.

In the same way, put methods write bytes from index.

MappedByteBuffer class

Overloaded force methods was added to MappedByteBuffer class.

  • MappedByteBuffer force(int index, int length)

Existing force method has no argument, and write memory-mapped file contents to the file forcibly. New overloaded force method also write memory-mapped file contents by index argument and length argument.

 

java.nio.file package

FileSystems class

FileSystem class defines 3 overloaded newFileSystem methods.

  • FileSystem newFileSystem(Path path)
  • FileSystem newFileSystem(Path path, Map<String, ?> env)
  • FileSystem newFileSystem(Path path, Map<String, ?> env, ClassLoader loader)

newFileSystem method is a factory method of FileSystem object, and uses URI for specifying the file system. newFileSystem also uses Path interface, but Classloader together.

New overloaded newFileSystem method specify the file system by Path ingterface, and use System class loader.

It is a little bit easier to deal with ZIP file or JAR file.as a file system.

jshell> var path = Paths.get("C:\\Program Files\\Java\\jdk-13\\lib\\src.zip")
path ==> C:\Program Files\Java\jdk-13\lib\src.zip

jshell> var fileSystem = FileSystems.newFileSystem(path)
fileSystem ==> C:\Program Files\Java\jdk-13\lib\src.zip

jshell> Files.list(fileSystem.getPath(".")).forEach(System.out::println)
./jdk.zipfs
./jdk.xml.dom
./jdk.unsupported.desktop
./jdk.unsupported
./jdk.security.jgss
./jdk.security.auth
./jdk.sctp
./jdk.scripting.nashorn.shell
./jdk.scripting.nashorn
./jdk.rmic
./jdk.pack
./jdk.net
    <<snip, snip, snip>>

jshell>

 

java.time.chrono package

JapaneseEra class

JapaneseEra indicates Japanese traditional era, and was added new era "REIWA" as constant. As you may know, the costant was backported to Java 8/11/12.

  • REIWA

 

javax.annotation package

ProcessingEnvironment interface

ProcessingEnvironment interface is used for annotation processing.

  • boolean isPreviewEnabled()

isPreviewEnabled method checked to use preview feature. If --enabled-preview option is set, isPreviewEnabled method returns true. If no, it returns false.

 

javax.lang.model package

SourceVersion enum

In every release, a constant is added in SourceVersion enum.

  • RELEASE_13

 

javax.lang.model.element package

ExecutableElement interface

ExecutableElement interface indicateds an element that enables to execute such as method of class/interface and constructor.

  • TypeMirror asType()

asType method returns TypeMirror object that indicates a type.

 

javax.tools package

StandardJavaFileManager interface

javax.tools package includes classes asociated with javac compiler, and StandardJavaFileManager interface is a file manager for the compiler.

  • Iterable<? extends JavaFileObject> getJavaFileObjectsFromPaths​(Collection<? extends Path> paths)

Existing getJavaFileObjectsFromPaths method has an argument as Iterable interface, but new overloaded getJavaFileObjectsFromPaths method uses Collection interface.

On the other hand, old getJavaFileObjectsFromPaths method was deprecated.

 

javax.xml.parsers package

DocumentBuilderFactory class

I didn't imagine that DOM parser was added new APIs!

  • DocumentBuilderFactory newDefaultNSInstance()
  • DocumentBuilderFactory newNSInstance()
  • DocumentBuilderFactory newNSInstance​(String factoryClassName, ClassLoader classLoader)

These 3 methods are factory methods to create DocumentBuilderFactory object using name space.

 

There are some APIs about security, but I don't have enough knowledge about these APIs. So, I skiped them.

2019/09/18

JEPでは語れないJava SE 13

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

アメリカ西海岸時間の9月17日にJava SE 13がリリースされました。

ちょうどサンフランシスコではOracle Code Oneが開催されていて、櫻庭も参加しています。OC1に参加しているのでなかなか書く時間がとれないのですが、恒例となっているのでJEPで提案されている以外のJava SEの変更をまとめておきます。

Java SE 13も変更はかなり少ないです。提案されたJEPは5個。ライブラリに関するJEPはなく、言語使用に関するJEPが2つです。

1つがswitchが文から式になるということ(JEP 354)。Java SE 12でもPreview機能で入っていましたが、再検討されて新たにPreview機能として入っています。値を返す時のyieldが一番の違いです。

もう1つが、テキストブロック(JEP 355) こちらはJava SE 12で入らなかったJEP 326 Raw String Literalの再検討版です。もちろん、テキストブロックもpreview機能なので、今後変更される可能性があります。

 

さて、本題のAPIの方です。こちらもそれほど変更は大きくありません。

今回もABC順にならんでいます。同じように、セキュリティ系のAPIはちゃんと理解していないので、省略してます。

 

廃止になったAPI

Java SE 13では2つのメソッドが廃止になっています。

いずれも、Java SE 9で@DeprecatedのforRemovalがtrueになったメソッドです。

  • java.lang.Runtime.traceInstructions(boolean)
  • java.lang.Runtime.traceMethodCalls(boolean)

Java SE 12以前のJavadocを見ていただければ分かりますけど、この2つのメソッドの説明は"Not implemented, does nothing." なぜ、今まで残していたのか不思議なくらいですねw

 

廃止予定のAPI

廃止予定APIの追加は多いです。

パッケージ

  • javax.security.cert

クラス

  • javax.security.cert.Certificate
  • javax.security.cert.X509Certificate

例外

  • javax.security.cert.CertificateEncodingException
  • javax.security.cert.CertificateException
  • javax.security.cert.CertificateExpiredException
  • javax.security.cert.CertificateNotYetValidException
  • javax.security.cert.CertificateParsingException

メソッド

  • java.lang.String.formatted
  • java.lang.String.stripIndent
  • java.lang.String.translateEscapes
  • javax.net.ssl.HandshakeCompletedEvent.getPeerCertificateChain
  • javax.net.ssl.SSLSession.getPeerCertificateChain

javax.security.certパッケージは、java.security.certパッケージを使うようにということです。javax.security.certパッケージはJava SE 9で@Deprecatedになったのですが、Java SE 13でforRemoval=trueになったということで、廃止することが決まったということです。

Stringクラスの3つのメソッドはJava SE 13で追加されたメソッドです。Java SE 13で追加されたのに、forRemoval=trueというのは、どういうこと?という感じですね。

これらのメソッドの機能については後述しますが、いずれもテキストブロックに関連しているメソッドなのです。つまり、テキストブロックがpreviewから正式な仕様に変更される時に、これらのメソッドも変更されるかもということを示しているわけです。

javax.net.sslパッケージの2つのメソッドもjavax.security.certパッケージに関連したメソッドです。HandshakeCompletedEvent.getPeerCertificateChainメソッドは返り値がX509Certificateクラスの配列なのです。今後はgetPeerCertificateChainメソッドではなく、同じクラスのgetPeerCertificatesメソッドを使うようにします。

SSLSession.getPeerCertificateChainメソッドも同じで、代わりにgetPeerCertificatesメソッドを使うようにします。

 

追加されたAPI

java.langパッケージ

JEPにはなっていないのですが、Java SE 13ではUnicode 12.1をサポートしています。その関連で2つのクラスに定数が増えました。

Character.UnicodeBlockクラス

UnicodeBlockクラスはその名の通り、Unicodeのブロックを表す定数を定義しているクラスです。Unicode 12.0で導入されたブロックが追加になりました。

  • EGYPTIAN_HIEROGLYPH_FORMAT_CONTROLS
  • ELYMAIC
  • NANDINAGARI
  • NYIAKENG_PUACHUE_HMONG
  • OTTOMAN_SIYAQ_NUMBERS
  • SMALL_KANA_EXTENSION
  • SYMBOLS_AND_PICTOGRAPHS_EXTENDED_A
  • TAMIL_SUPPLEMENT
  • WANCHO

Character.UnicodeScript列挙型

enumのUnicodeScriptにもUnicode 12.0で導入されたスクリプトが追加になりました。

  • ELYMAIC
  • NANDINAGARI
  • NYIAKENG_PUACHUE_HMONG
  • WANCHO

 

追記

Oracleの佐藤さんに、Java 13が対応しているUnicodeのバージョンが12.0ではなく、12.1と教えていただきました。本文は修正してあります。

なお、対応しているUnicodeのバージョンはjava.lang.CharaccterクラスのJavadocに記述してあるそうです。Java 13の場合は以下のように表記されています。

Character information is based on the Unicode Standard, version 12.1.

(Java 13 CharacterクラスのJavadocより引用)

 

Stringクラス

前述したように、Stringクラスにはテキストブロック関連のメソッドが3つ追加されました。しかも@DeprecatedのforRemoval=trueなので、コンパイル時に警告が出ます。

  • String formatted(java.lang.Object... args)
  • String stripIndent()
  • String translateEscapes()

J2SE 5でstaticメソッドのformatメソッドが導入されましたが、formattedメソッドはそれのインスタンスメソッド版です。

jshell>  import java.time.*

jshell> "%s%n".formatted(LocalDate.now())
|  警告:
|  java.lang.Stringのformatted(java.lang.Object...)は推奨されておらず、削除用にマークされ ています
|  "%s%n".formatted(LocalDate.now())
|  ^--------------^
$1 ==> "2019-09-17\r\n"

jshell>

formatメソッドもformattedメソッドも内部ではjava.util.Formatterクラスのformatメソッドをコールしています。

stripIndentメソッドは複数行からなる文字列の先頭文字がホワイトスペースだった場合、前詰めした文字列に変換するためのメソッドです。

jshell> var text = "  abc\n" +
   ...> "   def\n" +
   ...> "    ghi"
text ==> "  abc\n   def\n    ghi"

jshell> System.out.println(text)
  abc
   def
    ghi

jshell> System.out.println(text.stripIndent())
abc
 def
  ghi
|  警告:
|  java.lang.StringのstripIndent()は推奨されておらず、削除用にマークされています
|  System.out.println(text.stripIndent())
|                     ^--------------^

jshell>

なお、テキストブロックを使用すると、勝手に前詰めされます。コンパイル時にこのメソッドを使用しているかどうかまでは調べていないので、ぜひ調べてみてください。

translateEscapesメソッドはエスケープシーケンスを変換するメソッドです。

たとえば、"\n"という2文字で表されているエスケープシーケンスをU+000Aに置き換えます。

とはいうものの、このメソッドの使い道がイマイチよく分からないんですよね。文字列を出力する時には、置き換えられていたので、意識することはなかったのですが... どういう時に使うんだろう?

なお、このメソッドではUnicodeのエスケープは置き換えを行わないそうです。

 

java.nioパッケージ

Buffer系のクラスにメソッドがいろいろと追加されました。

Bufferクラス

Bufferクラスにはsliceメソッドがオーバーロードされました。

  • Buffer slice(int index, int length)

今まで使われていたsliceメソッドは引数なしでcurrent positionとlimitの間を切り出すメソッドでした。

オーバーロードされたのは明示的にインデックスと長さを指定して切り出すために使用されます。

実際には内部で、引数なしのsliceと同じような処理行っているので、使い勝手をよくするためのメソッドということですね。

jshell> var buffer = ByteBuffer.allocate(5)
buffer ==> java.nio.HeapByteBuffer[pos=0 lim=5 cap=5]

jshell> buffer.position(2)
$3 ==> java.nio.HeapByteBuffer[pos=2 lim=5 cap=5]

jshell> var buffer2 = buffer.slice()
buffer2 ==> java.nio.HeapByteBuffer[pos=0 lim=3 cap=3]

jshell> var buffer3 = buffer.slice(2, 3)
buffer3 ==> java.nio.HeapByteBuffer[pos=0 lim=3 cap=3]

jshell>

同じ切り出しを引数なしのsliceメソッドと、引数ありのsliceメソッドでやってみました。

なお、Bufferクラスはアブストラクトクラスなので、ByteBufferクラスを使用しています。

もちろん、他のCharBufferクラスなどでも引数ありsliceメソッドがオーバーロードされています。

ByteBuffer/CharBuffer/DoubleBuffer/FloatBuffer/IntBuffer/LongBuffer/ShortBufferクラス

それぞれのクラスにgetメソッドが2つ、putメソッドが2つオーバーロードされています。

Bufferクラスに追加されたsliceメソッドは返り値の方がBufferクラスなのですが、ByteBufferクラスなどでオーバーロードされたメソッドは返り値の型がそれぞれのクラスなので、Bufferクラスでは定義できないのでした。

ただ、使い道はどのクラスでも同じなので、ここではByteBufferクラスで説明します。

  • ByteBuffer get(int index, byte[] dst)
  • ByteBuffer get(int index, byte[] dst, int offset, int length)
  • ByteBuffer put(int index, byte[] src)
  • ByteBuffer put(int index, byte[] src, int offset, int length)

今までのgetメソッドはpositionの位置から読み込みを行うか、インデックスを指定して1バイト読み込むかのどちらかしかありませんでした。新しくオーバーロードされたgetメソッドはインデックスを使用して第2引数のバイト配列に読み込みを行います。

jshell> var b = new byte[]{0, 1, 2, 3, 4, 5}
b ==> byte[6] { 0, 1, 2, 3, 4, 5 }

jshell> var buffer = ByteBuffer.wrap(b)
buffer ==> java.nio.HeapByteBuffer[pos=0 lim=6 cap=6]

jshell> var bytes = new byte[2]
bytes ==> byte[2] { 0, 0 }

jshell> buffer.get(2, bytes)
$13 ==> java.nio.HeapByteBuffer[pos=0 lim=6 cap=6]

jshell> bytes
bytes ==> byte[2] { 2, 3 }

jshell>

ここでは、インデックス2から2バイト読み込んでます。

putメソッドも同じで、今まではpositionから書き込みを行うか、インデックスを使用して1文字の書き込みを行うだけだったのが、インデックスを使用してバイト配列で書き込みが行えるようになりました。

MappedByteBufferクラス

MappedByteBufferクラスにはforceメソッドがオーバーロードされました。

  • MappedByteBuffer force(int index, int length)

今までのforceメソッドは引数なしで、メモリにマップされた内容を強制的にファイルに書き出すというメソッドでした。オーバーロードされたforceメソッドはインデックスと長さを指定して強制的にファイルに書き出しを行います。

 

java.nio.fileパッケージ

FileSystemsクラス

FileSytemクラスでは、3種類のnewFileSystemメソッドがオーバーロードされています。

  • FileSystem newFileSystem(Path path)
  • FileSystem newFileSystem(Path path, Map<String, ?> env)
  • FileSystem newFileSystem(Path path, Map<String, ?> env, ClassLoader loader)

newFileSystemメソッドはFileSystemクラスのファクトリメソッドなのですが、今までは場所を指定するのにURIを使用していました。Pathインタフェースも使えたのですが、クラスローダ―を指定する必要がありました。

Java 13で追加された3種類はどれもPathインタフェースで場所を指定します。

ZIPファイルやJARファイルをファイルシステムとみなして扱うような時に使用するメソッドなのですが、パスで指定できるようになったので、少しだけ扱いやすくなりました。

jshell> var path = Paths.get("C:\\Program Files\\Java\\jdk-13\\lib\\src.zip")
path ==> C:\Program Files\Java\jdk-13\lib\src.zip

jshell> var fileSystem = FileSystems.newFileSystem(path)
fileSystem ==> C:\Program Files\Java\jdk-13\lib\src.zip

jshell> Files.list(fileSystem.getPath(".")).forEach(System.out::println)
./jdk.zipfs
./jdk.xml.dom
./jdk.unsupported.desktop
./jdk.unsupported
./jdk.security.jgss
./jdk.security.auth
./jdk.sctp
./jdk.scripting.nashorn.shell
./jdk.scripting.nashorn
./jdk.rmic
./jdk.pack
./jdk.net
    <<以下、省略>>

jshell>

 

java.time.chronoパッケージ

JapaneseEraクラス

日本の元号を表すクラスですが、令和が定数として追加されました。メジャーバージョンとしてはJava 13からということです。

  • REIWA

javax.annotationパッケージ

ProcessingEnvironmentインタフェース

アノテーションの処理を行う時に使用するインタフェースがProcessingEnvironmentインタフェースです。

  • boolean isPreviewEnabled()

プレビュー機能を使用する時にはコンパイル/実行時に--enable-previewオプションを使用します。isPreviewEnabledメソッドは--enable-previewが指定されていればtrue、いなければfalseを返します。

 

javax.lang.modelパッケージ

SourceVersion列挙型

毎度のお約束ですが、定数にJava 13が追加されました。

  • RELEASE_13

 

javax.lang.model.elementパッケージ

ExecutableElementインタフェース

ExecutableElementインタフェースは、クラスやインタフェースのメソッド、コンストラクタなど実行できる要素を表すためのインタフェースです。

  • TypeMirror asType()

ExecutableElementインタフェースで表している実行要素がメソッドなのか、コンストラクタなのか、初期化子なのかを判別するために使用します。

 

javax.toolsパッケージ

StandardJavaFileManagerインタフェース

javax.toolsパッケージはコンパイラ系のクラスが定義されているのですが、そこで使用するファイルマネージャがStandardJavaFileManagerインタフェースです。

  • Iterable<? extends JavaFileObject> getJavaFileObjectsFromPaths​(Collection<? extends Path> paths)

これまで使われていたgetJavaFileObjectsFromPathメソッドは引数の型がIterableインタフェースだったのですが、Collectionインタフェースを引数にとるメソッドがオーバーロードされました。

逆に引数の型がIterableインタフェースの方は@Deprecatedになっています。

 

javax.xml.parsersパッケージ

DocumentBuilderFactoryクラス

まさか、この期におよんでDOMパーサーに機能が追加されるとは思いもよりませんでしたw

  • DocumentBuilderFactory newDefaultNSInstance()
  • DocumentBuilderFactory newNSInstance()
  • DocumentBuilderFactory newNSInstance​(String factoryClassName, ClassLoader classLoader)

いずれも名前空間を認識したDocumentBuilderFactoryオブジェクトを生成するファクトリメソッドです。

 

他にもセキュリティ系のAPIに追加がありますが、よく分からないので省略します。

ということで、Java 13のAPIの変更をまとめてみましたが、やっぱり変更は少ないですね。

 

2019/06/15

JJUG CCC 2019 Spring

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

もう1月も前ですが、5月18日にJJUG CCC 2019 Springが開催されました。Oracle Codeの次の日ですね。

今回はProject LoomのFiberについてプレゼンしました。資料はこちら。

Fiberはいわゆる軽量スレッドです。

プレゼンではなぜ軽量スレッドが必要なのかという部分について、かなり時間をかけて説明しました。

OSに強く結びついたThreadを使った場合、コンテキストスイッチにコストがかかります。時間もかかるし、メモリも多く使用します。

これは、スレッドごとに用意されるJVM Stackをすべて退避させたり、もどしたりする必要があるからです。JVM Stackは、そのスレッドでコールされているメソッドコールのスタックで、メソッドで使われるローカル変数やオペランドスタックも含みます。

また、OSがスレッドのスケジューリングを管理しているため、コンテキストスイッチがいつ行われているかもJava側からは管理することができません。

そのために求められているのが、JVMで管理する軽量スレッド、つまりFiberというわけです。

これに対し、Fiberを使えば、ワーカースレッド上で動作するため、スケジューリングはJVMで管理でき、状態の退避用のメモリも少なくてすみます。

Fiberでは、スケジューリングには既存のFork/Join Frameworkが使用されます。コンテキストスイッチには処理の中断、再開のための仕組みが必要ですが、これはContinuationで行います。Continuationはいわゆる継続を実現させるための仕組みですが、JavaのContinuationは限定継続になります。

プレゼンの中ではContinuationをかなり強引にwait-notifyAllと同じようなものと説明してしまったため、誤解させてしまったのではないかと反省しています。もちろん、Continuationもwait-notifyAllも処理の中断・再開をするという機能はありますが、一般的なContinuationでできることは処理の中断・再開だけではありません。ちょっと説明不足でした。

しかし、今のところProject LoomではContinationを積極的に活用するようなシナリオはないように見えます。現状は、I/O待ちのためにパフォーマンスが落ちていることに対して、Fiberを使ってI/O待ちをなるべく解消することがメインの目的のようです。

これは、処理の中断・再開を行うFiberのparkメソッド、unparkメソッドがデフォルトのアクセス制御であることからも分かります。park/unparkを使用しているのは、ReentrantLockクラスなどのロック系のクラスや、java.nio.channelパッケージのソケット通信などのクラスなどです。

プレゼンの中では前日に行ったOracle Codeのデモについても説明しました。JDKに含まれているHTTPサーバーであるcom.sun.net.httpserver.HttpSErverクラスを使用して、Fiberを指定しているだけです。これだけで、既存のExecutorServiceインタフェースを使用した場合よりもスレッド数やスループットが向上しました。

とはいうものの、現状Fiberはそこまで速くありません。

コンテキストスイッチが起きないようにうまくタスク分けして、I/O待ちも多重化するなどして待たなければいけないスレッドを最小化するなどのチューニングを行えば、Fiberより高いパフォーマンスを得ることができます。

ただ、それをするには設計やチューニングなどの高度な知識や経験が求められます。Fiberを使うことで誰でも簡単にパフォーマンスを向上させられるということが、Fiberの意義の1つなのではないかと感じています。

また、Fiberのさらなるパフォーマンス向上のためにJVM Stackを操作することも考えられているようなので、今後に期待したいですね。

 

さて、以下は会場やsli.doでの質問とその回答です。

Q Fiberの中断前と再開後でワークスレッドが変わることがあるのか?

A. あります。

キターーーーーーー 「この分野は素人なのですが」な質問!!!

なんとか答えられてよかったですw

さて、現状はFiberはシリアライザブルではないのですが、シリアライザブルにする計画があります。このため、ワークスレッドが変化することもありますし、処理途中のFiberを他のCPUに移動させてそこで再開というシナリオも考えられます。

質問した伊藤さんも心配されていますが、ロガーのようにスタックトレースを保持させるようなものは、Fiberにするとやばいかもしれません。

Q. ある時点の処理で中断していたものを複数回再実行することはできるか?

A. 一般的な継続だとこれができるのですが、今のところJavaのFiberでは計画されていないようです。

Fiberは継続を行うための状態管理に既存のJVM Stackをそのまま使っています。そのため、再実行を行うには、JVM Stackを操作するバイトコードが必要になるはずですが、そこまでやるとかなり大がかりになってしまうためかもしれません。

Q. ワークスレッドは自動的に用意されるのか?

A. されます。

デフォルトではForkJoinPoolを利用してワークスレッドの割り当てを行っています。もちろん、他のスレッドプールに置き換えることもできます。

Q. OSによらないThreadがFiberだとしたら、Green Threadのようなもの?

A. まさにGreen Threadです。

Javaの初期のころ、Solaris向けのJavaはネイティブのスレッドではなく、JVMが管理するスレッドを使用していたのですが、それがGreen Threadです。

Q. Kotlinのcoroutineと何が違うのか?

A. Kotlinのことをよく知らないのですが、同じような機能のようですね。

Q. Continuationのscopeがよく分からない。コンテキストスイッチを行いたい複数のFiberからなるグループのようなもの?

A. 継続処理を行いたい範囲をしめすものです。

どこからでも自由に中断・再開を行うのは難しいので、継続ができる範囲を決めているという感じです。Fiberも内部でスコープを持っていて、Fiberのタスク処理の中だけで継続を行っています。

Q. ThreadとFiberの使い分け指針が知りたい

A. I/Oの待機やロックの取得を含む非同期処理であればFiberを使うのがよいと思います。

計算処理だけであるならパラレルストリームやFork/Join Frameworkを使いましょう。それ以外だったらThreadになると思いますが、今でもExecutorServiceにタスクを渡すのが主で、Threadを直接使うことはまずないはずです。

Q. 既存のThreadをFiberに置き換えるイメージがつかめません。ExecutorServiceでThreadを使うようなことはFiberでもできるのでしょうか。

A. Fiber.scheduleメソッドがExecutorService.submitメソッドのような感じです。

Fiber.scheduleメソッドはstaticメソッドなので、ExecutorServiceのようにExecutorsクラスでExecutorServiceインスタンスを生成して、それからsubmitするまでを行っているような感じです。

Q. Loom入りのJDKを含んだDocker Imageは公開されているか?

A. 私が調べたときにはなかったです。

Docker上でLoomのJDKをビルドしようとするとなぜか落ちてしまうので、私はローカルな環境でビルドしてからそれをコピーするDockerfileを作ってDockerのイメージを作ってました。

Q. Loomのリリース予定は未定だとしても、現時点での目標とかはあるのでしょうか?

A. 明確なリリース予定時期がFiberを作っている人たちの間ではあるのかもしれませんが、私には分からないです。

少なくとも、Windowsで動作できるようにならないとリリースはできないので、そこが最低限の目標となるのではないでしょうか。