2018/09/26

JEPでは語れないJava SE 11 - java.baseモジュール編

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

今日の早朝、Java SE 11がリリースされました。

Java SEの機能はJEPでまとめられていますが、JEPに入っていないこまごまとした変更もいろいろ入ってます。ということで、Java SE 10に引き続き、Java SE 11についてもまとめてみます。

量が多いので、今回はjava.baseモジュールだけです。他のモジュールも引き続きまとめるつもりです。

基本的にはABC順にならんでいます。重要度順にしようかと思ったのですが、量が量なので...

また、セキュリティ系のAPIはちゃんと理解していないので、省略してます。

 

廃止になったAPI

Javaは互換性を重視する言語ですが、Java 9から使われなくなった機能はほんとに削除対象になっています。

Java SE 11でも多くのAPIが廃止になっています。

モジュール

Java 11で一番大きな非互換性となるのが、Java EE関連のモジュールの削除です。これはJEP 320で提案されていました。

これらのモジュールはJava 9/10でも標準モジュールパスからは外されていましたが、Java 11でほんとうに削除されてしまいました。

  • java.se.ee
  • java.activation (JAF)
  • java.corba
  • java.transaction
  • java.xml.bind (JAXB)
  • java.xml.ws (JAX-WS)
  • java.xml.ws.annotation

JAFやJAXB、JAX-WSはJava EEのものを使うようにすればOKです。Mavenのセントラルレポジトリにも登録されているので、MavenやGradleを使われている場合はそちらを使うのが便利です。

CORBAは代替のAPIはないのですが、今さら使う人はいないでしょう。

また、Oracle JDKに含まれていたJavaFXはOracle JDKからも削除されてしまいました。

  • javafx.base
  • javafx.graphics
  • javafx.controls
  • javafx.fxml
  • javafx.media
  • javafx.web
  • javafx.swing

JavaFXはOpenJDKのOpenJFXプロジェクトで開発が進められています。Java SE 11に先立って、JavaFX 11もリリースされています。

JavaFXはバイナリの配布やJavadocも含めて、新しいJavaFXのサイトで公開されています。

クラス

セキュリティ系のAPIはいろいろと変化があります。

クラスも廃止されています。

  • java.security.Policy

メソッド

@DeprecatedアノテーションでforRemovalがtrueのメソッドで、以下のメソッドが廃止されました。

  • java.lang.Runtime.runFinalizersOnExit(boolean)
  • java.lang.SecurityManager.checkAwtEventQueueAccess()
  • java.lang.SecurityManager.checkMemberAccess(java.lang.Class, int)
  • java.lang.SecurityManager.checkSystemClipboardAccess()
  • java.lang.SecurityManager.checkTopLevelWindow(java.lang.Object)
  • java.lang.System.runFinalizersOnExit(boolean)
  • java.lang.Thread.destroy()
  • java.lang.Thread.stop(java.lang.Throwable)

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

廃止予定のAPI

Java SE 11では以下のAPIが廃止予定に追加されました。

クラス

  • java.util.jar.Pack200

インタフェース

  • java.util.jar.Pack200.Packer
  • java.util.jar.Pack200.Unpacker

Pack200クラスはJEP 336で提案されていました。

追加されたAPIも含めたDeprecatedなAPIはJavadocのDeprecatedで参照できます。

 

追加されたAPI

java.ioパッケージ

ByteArrayOutputStreamクラス

  • void writeBytes(byte[] b)

このメソッドはwrite(b, 0, b.lenght)と同じ処理になります。

FileReaderクラス

コンストラクタが2つ追加されました。

  • FileReader(java.io.File file, java.nio.charset.Charset charset)
  • FileReader(java.lang.String fileName, java.nio.charset.Charset charset)

やっと文字コードを指定できるようになりました。

FileWriterクラス

FileWriterクラスもFileReaderクラスと同様に、コンストラクタで文字コードを指定できるようになりました。

  • FileWriter(java.io.File file, java.nio.charset.Charset charset)
  • FileWriter(java.io.File file, java.nio.charset.Charset charset, boolean append)
  • FileWriter(java.lang.String fileName, java.nio.charset.Charset charset)
  • FileWriter(java.lang.String fileName, java.nio.charset.Charset charset, boolean append)

InputStreamクラス

  • static InputStream nullInputStream()
  • byte[] readNBytes(int len)

nullInputStreamメソッドは何も返さないInputStreamオブジェクトを作るためのファクトリメソッドです。

readNBytesメソッドはJava 9で追加されましたが、そのオーバーロードがさらに追加されました。

Java 9で追加されたreadNBytesメソッドは引数にバイト配列を指定する必要がありましたが、Java 11でのオーバーロードでは読み込み長だけ指定すれば、配列を返してくれます。

とはいうものの、ループなどで何度も読む場合はバッファを使いまわした方が効率がいいですし、一度ですべて読み込むのであればreadAllBytesメソッドを使うので、使いどころが難しいかもしれません。

OutputStreamクラス

  • static OutputStream nullOutputStream()

InputStreamクラスと同様に、OutputStreamクラスにも何もしないストリームを作るファクトリメソッドが追加されました。

Readerクラス

  • static Reader nullReader()

Writerクラス

  • static Writer nullWriter()

java.langパッケージ

CharSequenceインタフェース

  • static int compare(java.lang.CharSequence cs1, java.lang.CharSequence cs2)

staticメソッドで比較できるようになりました。

てっきり、シンタックスシュガー的なメソッドかと思ったら、1文字ずつ比較してましたよw

Characterクラス

  • static String toString(int codePoint)

char型変数からStringオブジェクトを生成するメソッドはありましたが、補助文字を使えるcodePointからもStringオブジェクトを作れるようになりました。

Character.UnicodeBlockクラス

Unicode 10に合わせて、ブロックを表す定数が18個追加されました。いっぱいあるので省略。

Character.UnicodeScript列挙型

こちらもUnicode 10に合わせた文字スクリプト名が10個追加されました。

Classクラス

  • Class<?> getNestHost()

入れ子になったクラスのホストクラスを返します。入れ子になっていないクラス、配列、プリミティブおよびvoidは自分自身を返します。

  • Class<?>[] getNestMembers()

入れ子になったメンバーを返します。

  • boolean isNestmateOf(Class<?> c)

引数で指定したクラスとホストクラスが同じであるかどうかを調べます。配列やプリミティブ型の場合はfalseが返るようです。

これらの3つのメソッドはJEP 181 Nest-Based Access Controlで提案されたものです。

Stringクラス

  • boolean isBlank()

文字列が空かホワイトスペースだけの場合、trueが返ります。

  • Stream<String> lines()

文字列を改行コードで区切って、ストリーム化します。

  • String repeat(int count)

引数で指定された回数だけ繰り返した文字列を作ります。たとえば、"a".repeat(3);だと"aaa"が返ります。

  • String strip()
  • String stripLeading()
  • String stripTailing()

文字列の先頭と末尾のホワイトスペースを取り除くためのメソッド。

striptメソッドが先頭と末尾、stripLeadingメソッドが先頭だけ、stripTailingメソッドは末尾だけ処理します。

先頭のホワイトスペースを取り除くtrimメソッドと動作が似ているのですが、trimメソッドはLatin-1のホワイトスペース(半角のスペースとタブ、改行)だけを取り除いているようです。

このため、全角のスペースなどを取り除くにはstripメソッドを使用する必要があります。

StringBufferクラス

StringBuilderクラス

この2つのクラスはComparableインタフェースを実装するようになりました。

このため、compareToメソッドが使えるようになっています。

java.lang.invokeパッケージ

java.lang.invokeパッケージではクラスが追加されました!!

Java 10ではクラスの追加はなかったので、久しぶりのクラスの追加です。

  • ConstantBootstrapsクラス

bootstrapというのは動的に処理を決めるInvokeDynamic命令で使われていた機構です。JRubyや、ラムダ式でInvokeDynamic命令が使われています。

InvokeDynamic命令はメソッドコールに使われていたのですが、Java 11では定数に対してInvokeDynamic命令と同様に使用できるCONSTANT_Dynamic命令(condyと略されることが多いです)が追加されました(JEP 309)。

ConstantBootstapsクラスは、このcondyのbootstap用のユーティリティクラスです。

このため、普通の開発者がこのクラスを使うことはまずないと思います。

なお、Java 11のjavacでは、condyを使ったバイトコードは生成されないです。実際に使うようになるのはJava 12以降ですね。

java.lang.refパッケージ

Referenceクラス

  • Object clone()

なぜ、cloneメソッドが追加されたかというと、Referenceクラスはクローンできないということを明示するためです。このため、Referenceクラスのcloneメソッドをコールすると必ずCloneNotSupportedException例外が投げられます。

そもそも、Objectクラスにcloneメソッドが定義されていることが間違いのもとなんですよね。

java.nioパッケージ

ByteBufferクラス

  • int mismatch(ByteBuffer that)

CharBufferクラス

  • int mismatch(CharBuffer that)

DoubleBufferクラス

  • int mismatch(DoubleBuffer that)

FloatBufferクラス

  • int mismatch(FloatBuffer that)

IntBufferクラス

  • int mismatch(IntBuffer that)

LongBufferクラス

  • int mismatch(LongBuffer that)

ShortBufferクラス

  • int mismatch(ShortBuffer that)

mismatchメソッドはバッファ同士を比較して、違いのあった相対的な位置を返します。同一の場合は-1が返ります。相対といっているのは、バッファを調べるときにpositionの位置からlimitまでを調べるからです。

positionよりも前の位置の値が異なっていても、mismatchメソッドではチェックしません。

java.nio.chanelsパッケージ

SelectionKeyクラス

  • int interestOpsAnd(int ops)
  • int interestOpsOr(int ops)

ノンブロッキング通信で使用するSelectionKeyクラスは、操作対象を表す定数が定義されています。この定数はビットで表されていて、ANDやORをとることができます。たとえば、OP_READは0b0001、OP_WRITEは0b0100になっています。

これらの現在の値はinterestOpsメソッドで取得/設定できますが、それに対しAND処理とOR処理を加えたのが上記の2種類のメソッドです。

interestOpsAnd(ops)メソッドはkey.interestOps(key.interestOps() & ops)と同じ処理になります。同様にinterestOpsOr(ops)はkey.interestOps(key.interestOps() | ops)です。

Selectorクラス

SelectionKeyクラスと同様、ノンブロッキング通信で使用されるSelectorクラスでは、ノンブロッキングで行う処理の記述がラムダ式で記述できるようになりました。

  • int select(java.util.function.Consumer<SelectionKey> action)
  • int select(java.util.function.Consumer<SelectionKey> action, long timeout)
  • int selectNow(java.util.function.Consumer<SelectionKey> action)

今までは、selectedKeysメソッドでSelectionKeyオブジェクトを取り出して、処理していましたが、それが以下のように記述できます。

    selector.select(key -> {
        try {
            if (key.isAcceptable()) {
                // accept の場合の処理
                ServerSocketChannel serverSocket = (ServerSocketChannel) key.channel();
                // Non-Blocking モードに変更
                serverSocket.configureBlocking(false);
                // Selector への登録
                serverSocket.register(selector, SelectionKey.OP_READ);
            } else if (key.isReadable()) {
                // データが送られてきたときの処理
                SocketChannel socket = (SocketChannel) key.channel();
                // 読み込み処理
            }
        } catch (IOException ex) {
            // 例外処理
        }
    });

例外処理をラムダ式内でやらないといけないのが、ちょっとイヤですけど、記述はかなり簡単になりました。

java.nio.fileパッケージ

Pathインタフェース

static Path of(java.lang.String first, java.lang.String... more)

static Path of(java.net.URI uri)

Pathインタフェースにはファクトリメソッドが追加されました。

前者は FileSystems.getDefault().getPath(first, more)メソッドをコールする実装になっています。後者はスキーマがfileであればデフォルトのファイルシステム、それ以外であれば扱えるかどうかをチェックしてから、FileSystemProviderクラスのgetPath(uri)メソッドをコールしています。

Filesクラス

  • static String readString(java.nio.file.Path path)
  • static String readString(java.nio.file.Path path, java.nio.charset.Charset cs)
  • static Path writeString(java.nio.file.Path path, java.lang.CharSequence csq, java.nio.file.OpenOption... options)
  • static Path writeString(java.nio.file.Path path, java.lang.CharSequence csq, java.nio.charset.Charset cs, java.nio.file.OpenOption... options)

Filesクラスでは、ファイルを一括で読み込むreadAllLinesメソッドはあったのですが、この返り値の型はList<String>でした。これに対し、改行コードも含んだ1つの文字列として返すのがreadStringメソッドです。

同様にwriteStringメソッドではCharSequenceオブジェクトで表される文字列を一括で書き込みます。

java.utilパッケージ

Collectionインタフェース

  • <T> T[] toArray(IntFunction<T[]> generator)

配列を生成するための処理を記述できるようになりました。

Optionalクラス

OptionalDoubleクラス

OptionalIntクラス

OptionalLongクラス

  • boolean isEmpty()

isPresentメソッドの逆です。

java.tuil.concurrentパッケージ

TimeUnit列挙型

long convert(java.time.Duration duration)

durationで表される期間をTimeUnitで表される単位に変換します。TimuUnit.NANOSECONDSであればdurationをナノ秒に変換して返します。

java.util.functionパッケージ

Predicateインタフェース

  • <T> Predicate<T> not(Predicate<? super T> target)

targetで表される条件の否定を行うPredicateオブジェクトを返します。

java.util.regexパッケージ

Patternクラス

  • Predicate<String> asMatchPredicate()

Java 8でPatternクラスにasPredicateメソッドが追加されました。このasPredicateメソッドはストリームの中間操作のfilterメソッドの引数に使えるようなPredicateオブジェクトを生成していました。

ただ、このPredicateオブジェクトは s -> s.matcher().find() と同じ動作なので、文字列の部分一致を調べることになります。

そうではなく完全一致を行うようにするのがasMatchPredicateメソッドです。

    Pattern pattern = Pattern.compile("bc");
    List<String> list = List.of("abc", "bc", "bcd");

    list.stream()
        .filter(pattern.asPredicate())
        .forEach(System.out::println);

    list.stream()
        .filter(pattern.asMatchPredicate())
        .forEach(System.out::println);

これを実行すると、前者はabc, bc, bcdのすべてが表示されますが、後者はbcしか表示されません。

java.util.zipパッケージ

Deflaterクラス

  • int deflate(java.nio.ByteBuffer output)
  • int deflate(java.nio.ByteBuffer output, int flush)
  • void setDictionary(java.nio.ByteBuffer dictionary)
  • void setInput(java.nio.ByteBuffer input)

DeflaterクラスはZLIB圧縮を行うためのクラスです。

新たに追加された4種類のメソッドはいずれもオーバーロードです。既存のメソッドはすべてbyte[]が引数だったのに対し、新しいオーバーロードメソッドは引数にByteBufferクラスを使うことができます。

Inflaterクラス

  • int inflate(java.nio.ByteBuffer output)
  • void setDictionary(java.nio.ByteBuffer dictionary)
  • void setInput(java.nio.ByteBuffer input)

InflaterクラスはZIB圧縮を展開するためのクラスです。

Deflaterクラスと同様に、引数としてByteBufferクラスを使うことができるようになりました。