JavaOne 2016 3日目 & 4日目 - Message in the (Panama) Canal
こんにちは、開発部の野口です。
案の定 3日目のレポートは飛ばしてしまいましたが……巻き返していきます。 例によって、特に印象に残ったものをピックアップしてお伝えします!
Connecting Oceans with Project Panama: A Journey into Native
JNI の置き換えや Vector API の追加を目指す Project Panama についてのセッション。
Project Panama という名前は(ご想像の通り)北アメリカと南アメリカの境にあるパナマ運河からきていて、”connecting the gap” をコンセプトとするプロジェクトです。つなぐのは、Java と Native との間の gap、ですね。
Project Panama は JDK 9 には入りません。
JDK 10 以降でのリリースを目指して、鋭意研究開発中です。
野心的な機能が色々と含まれますが、すべてを実装し尽くしてから出すというよりは、部分的に使えるようにして、早くリリースすることを目指しているそうです。
Java と Native とをつなぐ、安全で、簡単に使える、高速なインタフェースを構築することが大きな目標です。
Java がネイティブコードと連携するための方法としては JNI があり、また JNA をはじめとする、JNI の使用を容易にするためのライブラリも広く使われています。
Project Panama は、それらを「安全性、使用の容易さ、速さ」の 3 つの面で超えることを目指します。
よくばりですね!
簡単なデモもありました。
jextract というツールで C のヘッダを読み込んで自動生成されたクラス群を使って、OpenGL のライブラリを呼び出します。
▲ネイティブっぽい雰囲気の Java コード
実際のコードを見ると、想像以上にネイティブコードっぽい Java コード、つまりネイティブとの一対一対応に近いラッパーを Java のクライアントコードから触ることができていて、これらのクラス/インタフェース群がすべてコマンド一発で生成されるのだとしたら、かなりナイスです。
安全性についても色々と考慮されており、さらにこれでパフォーマンスも JNI を上回るとしたら……。
AutoCloseable や 関数型インタフェースといった近年 Java に入った機能も大いに活用して設計されており、たしかにこれならやれるのかも、と期待が持てます。
ただし、あくまで研究開発段階ということで、今後仕様や設計が変わる可能性は大いにあるとのことです。
実際、セッション終わりの質問タイムも紛糾しました。
まだまだ課題は山積みのようですが、業務上 JNI のつらさを味わうことがちょいちょいあるので、期待したいところです。
Thinking in Parallel
Stuart Marks と Brian Goetz というグルーヴィーな登壇者による、並列処理についてのセッション。
今後入る予定の新機能についての議論があるかなとも思っていましたが、案外そういうのはなくて、基礎的な内容でした。
にも関わらずここに書いているのは、とても面白かったから!
大まかに言って、前半は Stuart が Stream API の価値について説き、後半は Brian が並列処理についての議論をするという段取りでした。
ごく簡潔にまとめてしまうと、Stuart の主張は、従来の for ループを使うよりも、Stream API を使用するほうが常によい。
理由は、新しいから、カッコいいから、関数型だから……ではなく、「抽象性のレベルが(for ループよりも)上だから」。
ごもっともです。
たとえば C を使わずに Java を使うのと(細部にこそ違いはあれ)同じなのかなと思います。一方で、「それでも Java でなく C を使うケース」というのもあることを考えると、完全な論理ではないとも思いますが、少なくとも、(C 言語を使うのに十分な正当性が必要であるように)for ループを使うのには十分な正当性、たとえばパフォーマンスのボトルネックであることが特定されているとか、が必要と言えそうです。
一見 Stream で処理するのが難しそうな「値のリストをチャンクに分割する処理」も、「インデックスのストリーム」という考え方を導入することで Stream で処理できるよ、という例には目を開かされました。*1
それから、後半の Brian の主張はというと、こちらは「並列化するほうが常によい」……ではもちろんなく、必要なときにだけすべし、でした。
理由は、「並列化は最適化だから」。はい。
並列化はたいてい、メモリ空間と効率(省エネ)を犠牲にして、スループットを向上させるために行います。よって、その費用対効果が十分だと判断できる場合以外には、すべきではありません。
Stream API は並列処理をサポートしています。
ここで、Stream API で並列処理によってスループットが上がる可能性があるための条件として、
- データの数が多く、一件あたりの処理コストも高いこと
- データの(メモリ上での)局所性が高いこと
- 処理の分割コストが低いこと
- 最終的な処理結果の統合コストが低いこと
- 順序に依存しないこと
が挙げられていました。
美しいリストです……。
もちろん、これらの要素を感覚で判断して決めてしまうのではなく、実データ(少なくとも、それに近いデータ)による実測が必要です。(最適化ですから最適になっていることを確認しないと!)
なお、上の議論は値の計算処理を前提としていて、I/O が絡む場合は少し変わってきます。
Let’s Get Lazy: Explore the Real Power of Streams
『アジャイルプラクティス』や『Java による関数型プログラミング』などの著書を持ち、JavaOneでも例年数多くのセッションを担当している Venkat Subramaniam による遅延処理についてのセッション。
去年は縁がなく、今年初めて彼のセッションを取ったのですが、さすが期待通りの内容でした。
まず Haskell の動作や Scala の lazy キーワードによる遅延評価を紹介したのち、Javaでは Supplier のラムダ式で同じようなことができるよね……、といった具合に、一歩一歩下地を作ります。
個人的には、評価した値を再利用するパターンも何か紹介してくれるかなと期待していた(結局なかった)ので、そこにはやや不満もありましたが、全体としての構成と運びが見事すぎて、帳消しになりました。
後半は、Stream API がいかに lazy であるかの紹介。
Stream は終端処理が呼ばれるまではあくまでパイプラインを組むにすぎず、各種の条件(filter)や変換(map)は終端処理を呼んだ時点でまとめて処理されます。
そのため、個々の処理が行われる回数は、従来の for ループで効率的にロジックを組んだ場合とまったく変わらない。ということを、実際の動くコードで、デバッグプリントも使いながら巧みに説明します。
▲なんかペンみたいなやつでパイプラインを示す
▲デバッグプリントでどのロジックが何度呼ばれたかを示す
どれも既に知っていることなのですが、よく整理された説得力のある説明で、知識が更新され、定着していきます。
終盤には無限ストリームを説明し、またリストを返すメソッドをストリームを返すメソッドにリファクタリングすることで、行われる処理の量(実行時間)を大きく削減するというデモも行いました。
この辺のコンセプトは彼の著書である『Java による関数型プログラミング』でも説明されている(されていた……はず)のですが、こうして説明を受けることで本当に明日から使える知識になります。
こういうところ(すぐれた教師の教えを直接受けられること)にも、JavaOne のような技術カンファレンスの価値はあります。
Ask the JDK Architects
去年も色々な面白トークを聴くことができたこのセッション。
今年は Mark Reinhold、John Rose、Brian Goetz の 3 名が登壇して、参加者からの数多くの質問に答えました。
▲The JDK Architects
今年のキーノートでまさに Brian が発表していたローカル変数の型推論について、去年も話題に上がっていた(気がする)「Java で一番後悔していること」、果ては彼らが好きな IDE まで……。
いくつかピックアップして紹介したいのですが、いまいち聞き取れなかったところの補完をするのに手持ちの iPhone *2 だけでは心許ないので、日本に帰ってから補足します!!
Oracle Appreciation Event
そして……会社から JavaOne 行かせてもらってる組として役得としか言いようのないこのイベント……!
▲今年は AT&T パークで行われました
Sting のステージ開始から 2 曲目で早々に Gwen Stefani が(再)登場し、一緒に「Message in a Bottle」を歌うなどしていました。
別々のスターが同時に二人ステージ上にいる状況に混乱して、少し泣きそうになりました。
▲Sting & Gwen Stefani!!
JavaOne 2016 も残すところあと一日。
最後(蟹 One)まで気を抜かず、励みます。