新たな歴史の1ページ~Oracle Code One 2018現地レポート

Oracle Code Oneレポート】Javaの進化は止まらない―将来導入が計画されている新機能とは

2018年10月22日から25日にかけての4日間、米サンフランシスコのMoscone CenterにおいてOracle主催の開発者向けイベント「Oracle Code One 2018」が開催されています。これは、これまでは「JavaOne Conference」として開催されていたイベントの後継となるもので、対象となる技術の裾野を広げてエンジニア同士のコラボレーションを促進しようという目的で名称が変更されました。

今回のOracle Code Oneでは、とくにJavaのコア機能に関わる発表がとくに注目されているように感じられます。その背景には、昨秋に公開されたJDK 9からJDKのリリースモデルが大幅に変更され、アップデートの速度が格段に早くなったという事情があります。そこで本記事では、現在開発が進められているJavaの新機能のうち、とくに重要とされる4つのプロジェクトについて取り上げます。

Javaの新機能はどのように決まるのか

そもそも、将来のJavaに導入される新機能はどのように決定されるのでしょうか。現在、JDKのコア機能の開発はOpenJDKプロジェクトが担っています。

OpenJDKプロジェクトでは、将来のJavaへの導入が検討される機能要望を「JEP(JDK Enhancement Proposals)⁠⁠」という形でまとめています。新機能の要望がJEPとして認可されれば、その機能の重要性やほかのJEPとの依存関係などを考慮して優先度が付けられ、担当者やターゲットとするJDKのバージョンなどが協議されます。

気をつけなくてはいけないのは、JEPはあくまでも提案であり、JEPに登録されたからといって必ずしも将来のJDKに導入されるとは限らないということです。

JEPの情報はこのページで公開されています。それぞれのJEPのターゲットとなるJDKバージョンを確認すれば、将来のJDKにどのような機能が追加されるのかがある程度見えてきます。たとえばJDK 12をターゲッチとしたJEPとしては、JEP325、JEP326、JEP340、JEP341があります。JDK 12にはこの4つの変更が加わる可能性が高いということです。

なお、各バージョンの最終的な仕様の決定は、従来通りJCP(Java Community Process)にしたがって行われます。Java 12のJSRはJSR 386です。

大きなインパクトのある機能については、JEPに登録されるだけでなく、OpenJDK内にサブプロジェクトを発足させて開発を行うケースもあります。そのようなプロジェクトは、OpenJDKの公式サイトの左側にある「Projects」の一覧から探すことができます。Oracle Code Oneでは、これらのプロジェクトのうち以下の4つがとくに重要度の高いものとして繰り返し取り上げられました。

この4プロジェクトの成果物は、将来的にJDKに導入される可能性がとくに高いものとして注目されています。実際、一部の機能は先行してすでにリリース済みのバージョンに導入されていますし、前述のように明確にJDK 12をターゲットとしたものもあります。

初日のキーノートでもMark Reinhold氏が1時間近くも使ってデモを披露したほどであり、とくに力を入れて開発されていることが分かります。

任意のプリミティブ型を作れる「Project Valhalla」

Project Valhallaは、JVMおよびJava言語の型に関する定義や実装を拡張するプロジェクトです。本稿執筆時点では、次のような機能が提案されています。

Value Typesは、intのようなプロミティブ型と同じ挙動をする任意の型を定義できるようにする拡張です。具体邸には、クラスを定義する際に特別なキーワードを付けることで、そのクラスのオブジェクトは参照を経由しないで値を保持できるようにメモリ上に展開されます。これによって、コード上ではクラスと同じように見えながら、実際にはプリミティブ型のようには参照のオーバーヘッドが無い、メモリ内でより効率的にレイアウトされる型を作れるようになります。

通常のクラスのメモリレイアウトの例
通常のクラスのメモリレイアウトの例
Value Typesのメモリレイアウトの例
Value Typesのメモリレイアウトの例

Generic Specializationは、Genericsに対してプリミティブな型の引数によるインスタンス化をサポートするというものです。従来のGenericsの型引数は、intなどのプリミティブ型には対応していませんでした。その代わりに、パフォーマンスを考慮した場合に備えてIntStreamのような専用のクラスが用意されていました。

しかし、Value Typesが実現した場合、Value Typesはプリミティブ型のように振る舞うため、この制約が非常に大きな負担となります。そこで、Generic Specializationを同時に実現することで、Value TypesもGenericsの型引数として利用できるようにしようというわけです。

ネイティブライブラリを効率的に呼び出す「Project Panama」

Project Panamaは、JVM上で動作するプログラムと、C言語をはじめとするネイティブのプログラムをよりシームレスに繋げされるようにするAPIを定義するプロジェクトです。関連するJEPとしてはJEP 191: Foreign Function InterfaceJEP 338: Vector APIなどが挙げられています。

現状、Javaのプログラムでネイティブのライブラリを使用したい場合には、JNI(Java Native Interface)を利用するしかありません。しかし、JNIの仕組みは複雑であり、適切に使用するにはC/C++のコードに関する知識に加えて、JVMの挙動に対する理解が必要です。また、ヒープ外のデータをモデリングするための方法が用意されていないという点も問題のひとつとして挙げられています。

これに対して、外部の(Java以外の)関数によりシームレスにアクセスするためのインタフェースを提供することで、JNIの問題を解決しようというのがProject Panamaの目的になります。具体的には、次の例のようにヘッダや構造体、コールバックなどをアノテーションを付加したインタフェースによって宣言できるような方法が検討されています。

リスト Panamaによるネイティブ関数のヘッダ定義の例
@NativeHeader(declarations="getpid=()i32")
interface Getpid {
    int getpid();
}
...
var _lib = Liberaries.bind(
                    MethodHandles.lookup(),
                    Getpid.class);
_lib.getpid();
JNIによるネイティブ関数呼び出しのワークフロー
JNIによるネイティブ関数呼び出しのワークフロー
Project Panamaによるネイティブ関数呼び出しのワークフロー
Project Panamaによるネイティブ関数呼び出しのワークフロー

ヒープ外のデータモデリングについては、ネイティブのポインターや配列のモデルを定義するためのPointerArrayといったクラスを提供する方法が提案されています。

軽量スレッドを実現する「Project Loom」

Prject Loomは、JVMに対してFiberと呼ばれる軽量なスレッドや、継続 (Continuations) と呼ばれる機能を追加することを目指しているプロジェクトです。

Fiberは、通常のスレッドとまったく同じように使うことができる一方で、通常のスレッドよりも極めて軽量で効率的な動作を実現するものです。Fiberはユーザモードで実装されるため、JVMによって完全にスケジュール管理されます。そのため、カーネルモードで実装されるスレッドに対して、メモリフットプリントやスイッチングにおいて高い効率を実現できます。具体的には、FiberはConcurrent APIのForkJoinPoolを使用してスケジューリングされます。

継続とは、"プログラム実行中のある時点においてまだ評価されていない残りの計算"を意味する概念です。Project Loomで実現しようとしているのは、この継続のうちの「限定継続(Delimited Continuations⁠⁠」と呼ばれるものです。限定継続というのは、継続に対して、残りの計算の範囲を明確にしたものです。限定継続は、呼び出されるとその範囲の終わりの部分まで処理を進めてから呼び出し元に戻ります。

Fiberは、ForkJoinPoolのスケジューリングと、この新しく導入される限定継続を組み合わせることによって、軽量なスレッドを実現するとのことです。限定継続そのものがFiberのために追加される機能ですが、汎用性が高いため、独立したAPIとして公開される予定だそうです。Project Loomが導入されれば、これまでスレッドで実装していた並列処理の多くをFiberに置き換えることができ、大幅な高速化を実現することができます。

Java言語を進化させる「Project Amber」

Project Amberは、Java言語に対する、比較的インパクトの小さい言語仕様の拡張を継続的に行っていくプロジェクトです。本校執筆時点では、このプロジェクトには以下のようなJEPが含まれています(カッコ内はリリースターゲットのJDK⁠⁠。

見てのとおり、すでにリリース済みの機能もあります。たとえば型を指定せずにvarキーワードを使って変数宣言できるようになったJEP 286はJDK 10で導入されて話題になりました。

このうち、JDK 12での導入が有力視されているのはJEP 325とJEP 326です。JEP 325はswitchの拡張です。これまで、switchは文として扱われていましたが、これを式としても扱えるように拡張しようというものです。具体的には、次のように戻り値を扱うことができるようになります。

リスト Switch Expressionsの例
int numLetters = switch (day) {
    case MONDAY, FRIDAY, SUNDAY -> 6;
    case TUESDAY -> 7;
    case THURSDAY, SATURDAY -> 8;
    case WEDNESDAY -> 9;
};

ある変数に入れる値をswitchで切り分けたい場合など、これまではすべてのcaseで変数に代入したりといった使い方をする必要がありましたが、式として使えるようになることでより効率のいい書き方ができるようになります。

JEP 326は文字列リテラルの拡張です。次の例ように、バッククォート(`)を使うことで、改行やダブルクォート(")などを含む文字列を、エスケープなしで記述できるようになります。これに関連して、インデントを扱うためのalign()やindent()といったメソッドも追加されます。

リスト Row String Literalsの例
String html 
    = `<html>
        <body>
            <p>Hello World.</p>
        </body>
       </html>`;

このほか、JEP 302はラムダ式に対する細かな修正、JEP 305はパターンマッチングをmatchesキーワードやswitchの条件の中で使えるようにするというものです。JEP 301はenumでGenericsを使えるようにしようという拡張になります。まだドラフトの段階で正式なJEPにはなっていませんが、メソッド定義の文法を拡張するConcise Method Bodiesという提案も含まれています。

上記に加えて、Oracle Code Oneの基調講演ではデータ保持用のクラスを定義できるようにする拡張機能のデモも披露されています。これはC#のrecordクラスやKotlinのdataクラスのように、データ保持用のクラスをコンパクトに宣言できるようにするというものです。次のように、recordキーワードを使って記述する方式が提案されています。

リスト データ保持用クラスの記述例
record Point(double x, double y) {
    //...
}

次期バージョンのリリースは2019年3月

さて、次期バージョンであるJDK 12のリリース予定は2019年3月です。9月末にJDK 11がリリースされたばかりですが、もう数ヶ月後には上記に挙げた拡張機能のうちのいくつかは使えるようになるということです。JDK 12はLTSの無いバージョンではありますが、そこに追加される新機能は当然ながら次のLTSバージョンでも有効なので、無視していいというわけではありません。

Javaの進化のスピードをこれまでと同様に考えていたら、あっという間に取り残されてしまうことになるでしょう。今年のOracle Code Oneではそのことを強く実感させられました。最新の情報をキャッチアップしながら、常に先のバージョンを見据えて準備しておくことが大切です。

おすすめ記事

記事・ニュース一覧