ぺんぎんらぼ

お笑いとマンガ好きなしょぼしょぼWeb系エンジニアの日記です。たまに絵を描きます。

お笑いとマンガ好きなしょぼしょぼWeb系エンジニアの日記です

Java15の新機能・変更点

Java誕生から25周年を迎える、2020年9月15日にJava15がリリースされました。

forest.watch.impress.co.jp

Java15の新機能・変更点について解説します。

339: Edwards-Curve Digital Signature Algorithm (EdDSA)

暗号化署名のアルゴリズムで、エドワーズ曲線デジタル署名アルゴリズム (EdDSA) のサポートが追加されました。

以下のように署名アルゴリズム名に"Ed25519"を指定することで、デジタル署名オブジェクトを生成できます。

KeyPairGenerator kpg = KeyPairGenerator.getInstance("Ed25519");
KeyPair kp = kpg.generateKeyPair();
Signature sig = Signature.getInstance("Ed25519");
sig.initSign(kp.getPrivate());

360: Sealed Classes (Preview)

Sealed Classesは、特定のクラスしか継承できないクラスを宣言するものです。

Javaのクラスは、すべてのクラスで継承可能で、継承させたくない場合はfinalで修飾することで、すべてのクラスで継承不可能にできました。
以下のようにsealedで修飾したクラスを宣言することで、permitsキーワードで指定したクラスでのみ継承可能な親クラスを作成できます。

public abstract sealed class Fruits permits Apple, Orange {
    public abstract String name();
}

この例では、抽象クラスのFruitsは、Appleクラス、Orangeクラスでのみ継承可能なクラスになります。

また、この機能追加に合わせて、Classクラスに以下のメソッドが追加されています。

  • boolean isSealed() - このクラスがSealedクラスか否かを返す。
  • ClassDesc[] permittedSubclasses() - このクラスが継承を許可しているクラスをClassDescオブジェクトの配列で返す。

371: Hidden Classes

他のクラスから直接使用できない隠しクラスを生成する機能です。

Javaは、コンパイル時にクラスファイルが生成され、それが実行時にクラスローダーに読み込まれますが、一部、実行時に動的に生成されるクラスがあります。ラムダ式やプロキシクラスなどがそれにあたります。
動的に生成されたクラスはリフレクションで外部から参照可能でしたが、この隠しファイルは動的に生成され、かつ、外部から参照不可能なクラスになります。

この隠しクラスは外部からの参照を制限して、利用可能な範囲を限定的にするために使用されます。

また、この機能追加に合わせて、Classクラスに以下のメソッドが追加されています。

  • boolean isHidden() - このクラスが隠しクラスか否かを返す。

372: Remove the Nashorn JavaScript Engine

JavaScriptエンジン「Nashorn」の削除。

Java8で導入されたJavaScriptエンジン「Nashorn」が削除されました。
Java11の時点で、JDKとしてメンテナンスするのは重い機能、ということでDeprecatedになり、今回のJava15で削除されることとなりました。

これに伴い、以下のモジュールが削除されます。

  • jdk.scripting.nashorn
  • jdk.scripting.nashorn.shell

373: Reimplement the Legacy DatagramSocket API

UDPを扱うDatagramSocket APIを、より簡潔で近代的な実装に作り直し。

メンテナンス性を向上させるために、UDPを扱うDatagramSocket APIの実装の見直しです。

374: Disable and Deprecate Biased Locking

バイアスロッキングが無効・非推奨になりました。

VectorやHashtableのような同期が必要な時、競合を防ぐためにロックする方法として、バイアスロッキングという方法が使用されていました。
しかし、最近のプロセッサは同期化の処理効率が上がっており、このバイアスロッキングを使用しても効果が得られず、むしろパフォーマンス低下につながるケースもあるため、Java15では無効になりました。

Java VM起動時にオプション「-XX:+UseBiasedLocking」を指定することで有効化することが可能です。

375: Pattern Matching for instanceof (Second Preview)

instanceofを使ったパターンマッチングです。

これは、すでにJava14でプレビューとして追加されたものが機能の変更なしにJava15ではセカンドプレビューとして入ってます。つまり、Java15で正式機能に格上げするのは時期尚早だけど、特に追加すべき機能もなかった。ということでしょう。

377: ZGC: A Scalable Low-Latency Garbage Collector

テラバイトレベルの巨大なヒープサイズも対応した低遅延なGCを正式版に格上げ。

Java11で実験的に導入されたGCが正式版になりました。
Java11では、Java VM起動オプション「-XX:+UnlockExperimentalVMOptions」を指定しないと有効になりませんでしたが、Java15からはオプションなしで有効になります。

378: Text Blocks

複数行文字列リテラルを正式版に格上げ。

Java13のプレビュー、Java14のセカンドプレビューを経て、Java15で正式版になりました。

文字列をダブルクォート3つで括ることで、複数行にわたるテキストを一つの文字列として扱うことができます。

var str = """
    一章
    二章
        一節
    """;

このコードでは、変数strに以下の文字列が代入されます。

一章
二章
    一節

注目すべき点は、コード上のインデントは一番浅い部分に合わせて、空白が削除されることです。そして、改行はそのまま文字列に反映されることです。

行末にバックスラッシュをつけることで改行をエスケープすることもできます。

var str = """
    今日は\
    いい天気です。
    """;

このコードでは、変数strに以下の文字列が代入されます。

今日はいい天気です。

379: Shenandoah: A Low-Pause-Time Garbage Collector

数百ギガバイトレベルの高速なG1ガベージコレクションを正式版に格上げ。

Java12で実験的に導入されたG1GCが正式版になりました。
Java12では、Java VM起動オプション「-XX:+UnlockExperimentalVMOptions」を指定しないと有効になりませんでしたが、Java15からはオプションなしで有効になります。

381: Remove the Solaris and SPARC Ports

Solaris/SPARC, Solaris/x64, Linux/SPARC向けのソースコードを削除、ビルドからも外されます。

383: Foreign-Memory Access API (Second Incubator)

Javaヒープ外部にあるメモリに安全かつ効率的にアクセスできるようにするためのAPIの導入です。

以下のように、MemorySegmentクラスのallocateNativeメソッドでメモリを確保して、VarHandleクラスのsetメソッドでメモリに値を格納します。

VarHandle intHandle = MemoryHandles.varHandle(int.class, ByteOrder.nativeOrder());

try (MemorySegment segment = MemorySegment.allocateNative(100)) {
    MemoryAddress base = segment.baseAddress();
    for (int i = 0; i < 25; i++) {
        intHandle.set(base.addOffset(i * 4), i);
    }
}

Java14でインキュベータ(育成期)として導入、Java15でもセカンドインキュベータです。正式版までの道のりは長いかも。

384: Records (Second Preview)

不変のデータを保持するRecordクラスのセカンドプレビューです。

不変のデータを格納するPojoのようなものです。コンストラクタやgetter、equals、hashCode、toStringが自動的に生成されるPojo、という認識でOKです。

record Employee(String name, String skill) {}

使い方はコンストラクタでオブジェクトを生成して、変数名と同名のメソッドで値を取得します。

Employee employee = new Employee("yamada", "Java");
String name = employee.name();
String Skill = employee.skill();

Java14でプレビューとして導入されたRecordクラスが、Java15ではフィードバックを反映してセカンドプレビューになりました。Java16で正式版に格上げされそうです。

385: Deprecate RMI Activation for Removal

将来の削除のために、RMI アクティベーション・メカニズムが非推奨になります。

RMIとは、Remote Method Invocationの略で、別サーバのJavaメソッドを呼び出すための通信方式です。
昨今の分散システムは、Webサービスで実装することで、ファイアウォールやリクエストのフィルタリング、認証など、セキュリティに関する機能が使用できますが、RMIには、これらのメカニズムは存在しない時代遅れのものです。

これに伴い、java.rmi.activationパッケージがDeprecatedになっています。