ランチがおいしくないのはいつものことなのですが、今年みながそろってまずいと言っているのがサンドウィッチについてくる豆料理。
レンティスやひよこ豆、フェイジャオンなどを使った煮込み料理なのですが (日によってレシピが違っています)、日本の豆料理とはかけ離れているからかもしれません。でも、アラビアなどで普通に食べられている料理なので、櫻庭にはそれほど違和感がないんですよね。というか意外においしいと思っていました。でも、食べ慣れていないものを食べると、そんなものなのかもしれませんね。
さて、今日は夕方から Treasure Island でライブがあるので、セッションも早じまいです。ということで、今日は BOF はなしで、以下の 4 セッションを聴講しました。
今日の最後の Date & Time API は、月曜日の Date & Time API のセッションとあまり変わらず... まぁ、そんなものか...
CON2624 Modeling, Texturing, and Lighting Mesh Geometry in JavaFX 3D
スピーカは John Yoon。この人は Keynote で紹介された 3D の Duke のチェスをモデリングした人らしいです。
といことで、あまり Java のコードは出てきません。外部のモデリングツールで作成したものを、どうやって Java に持ってくるかところが中心になります。このセッションでは Blender と Maya でデモをしていました。
ところで、今年の JavaOne は部屋が明るくしてあります。去年までは部屋をかなり暗くしていて、スピーカがいることは分かっても、細かい表情などは全然分からないぐらい。それが不評だったのか、今年は一転して明るくなりました。
一部のセッションでは、資料のコントラストが低くて見にくい部分もあったのですが、全般的にはよかったと思います。
ところが、このセッションだけは以前のようにまっくら。初日、2 日目とやってきて明るすぎと文句が出たのかと思いましたけど、全体を通しても暗かったのはこのセッションだけ。やっぱり、Blender や Maya の画面をよく見せるというためなのかもしれません。そのせいもあって、このセッションは写真なし。いちおう撮ったのですが、何が写っているのか判別するのが大変なぐらいだったのです。
ついでですけど、今年使用しているプロジェクタがとても静か。今までのはファンがかなりうるさかったのですが、ファンの音も気にしなければ全然気がつかないぐらい。いろんなところで技術革新は行われているんですね。
さて、本題に戻って。
まずはじめに、Java で 3D のモデルを書いていく方法から。頂点を指定して、テクスチャをマッピングして、表面を指定してとやっていくのですが、単純なオブジェクトでも結構大変。これで複雑なモデルを Java で書くのは考えられないよね、ということで Blender と Maya です。
Blender や Maya で作成したモデルは、Keynote でも使用していた 3D Viewer で読み込みます。
かれはモデリングを切り紙にたとえていっていました。切り紙って伝わらないと思うんだけど、大丈夫なのかなぁ。いちおう、切り紙と折り紙は違うものでと話していましたが。
切り紙にたとえたメインは U-V マッピング。確かにこれは切り紙かもしれません。
後半はコードが全然出ないで、Blender と Maya でどうやってモデルを作っていくかのチュートリアルになってしまいましたが、こういうのを見る機会がなかなかないので、個人的にはおもしろかったです。
CON7942 Java 8 Streams: Lambda in Top Gear
スピーカは Brian Goetz と Paul Sandoz。Brian Goetz のセッションは 3 つ目ですが、このセッションは Stream に絞ったものです。
それにしても、このセッションはすごい行列。やはりみなの関心が高いんですね。
コレクションなどに対する Aggregate Operation (集約的操作とでも訳すのでしょうか) には、歴史的にループが使われてきました。しかし、基本的にはシーケンシャルでスケールしません。
これに対する Java SE 8 の答えが Stream というわけです。
はじめの例として NY のバイヤーが売り上げた合計を求めるには、外部イテレータでは次のように記述してきました。
int sum = 0;
for (Transaction t: txns) {
if (t.getBuyer().getState().equals("NY")) {
sum += t.getPrice();
}
}
これに対して、Stream では次のように記述します。
int sum = txns.stream()
.filter(t -> t.getBuyer().getState().equals("NY"))
.mapToInt(t -> t.getPrice())
.sum();
パラレルに処理するのであれば、stream() を parallelStream() に変更するだけです。
Brian は Stream の方が読みやすいというのですが、これは慣れないと読みにくいですね。慣れればなんともないですけど。
今までの手法と Stream を比較すると、今までのループはコレクションの個々の要素について扱っているのに対し、Stream ではデータセットに対して扱っているという違いがあります。
また、従来が how だったのに対し、Stream は what だといいます。
ここから Stream の内部構造に入っていきます。
先ほどの例だと、Stream に対して filter と map、sum が使われていました。しかし、中間の filter と map はその場では処理されません。最後の sum ですべの処理が行われます。
つまり、filter, map, sum で 3 回のループが回るのではなく、filter と map は処理が遅延され、最後の map の 1 回だけイテレーションされます。
このような Stream に対する処理の連なりを、Brian はパイプラインと呼んでいます。
各パイプラインはソースを持っています。ソースは Stream の生成の方法によって異なります。Collection に対して Stream を生成した場合は、Collection のコンクリートクラスが、たとえば ArrayList などがソースになります。
このソースによって、Stream の性質が決まります。たとえば、ArrayList であれば SIZED と ORDERED。つまり、サイズと順番があるというわけです。
中間のオペレーションは処理が遅延されます。このオペレーションによっては Stream の性質を変更します。たとえば、map は SIZED は保持しますが、SORTED などは保持されません。
そして、最後のオペレーションでソースをたどって処理を行っていきます。終端のオペレーションとなるのは reduce, collect, sum, min, forEach などがあります。
もし、Stream でステートを持つような処理を行っている場合は、reduce もしくは collect を使用してステートレスにします。
たとえば、トランザクションから Seller だけを新たなリストにしたい場合を考えます。
List<Person> sellers = new ArrayList<>();
txns.maps(Txn::getSeller)
.forEach(s -> sellers.add(s));
と記述すると、ステートを持ってしまいます。このコードは下のように書き換えます。
List<Person> sellers = txns.maps(Txn::getSeller)
.collect(Collectors.toList());
Collectors クラスには toList 以外にも groupingBy などのメソッドが定義されています。
後半は Paul Sandoz がパラレル化について。
Java SE 7 で導入された
Fork/Join は低レベルすぎて、なかなか使いどころが難しい。
そこで、ParallelStream が登場します。
ParallelStream を考えた場合、デターミニスティックかどうかが重要になります。つまり、以下のコードで得られた結果は同一にならなくてはなりません。
List s = ...;
List r1 = s.stream().map(...).collect(Collectors.toList());
List r2 = s.parallelStream().map(...).collect(Collectors.toList();
assertEquals(r1, r2);
これに対して、以下の例はデターミニスティックである必要はありません。
Txn t1 = s.stream().filter(t -> t.getPrice() > 100).findAny();
Txn t2 = s.parallelStream().filter(t -> t.getPrice() > 100).findAny();
もちろん、デターミニスティックな場合の方がパラレル処理が難しくなります。
Stream のパラレル処理は、Fork/Join をベースとして作られているので、分割統治法で処理されます。実際に、sum や reduce などがどのように処理されるのかを解説しました。
toArray などの出たーミニスティ行くな処理をする場合には、分割した個々の要素が対応するインデックスを保持しておき、結果用の Array の適切なインデックスに結果を書き写していくということを行います。
ここでパフォーマンスの話。
パラレル処理したとしても、すべての場合でパフォーマンスが向上するわけではありません。シーケンシャルの方が速いこともあります。
Stream の終端の処理のマージ処理が大変であったりすると、パフォーマンスが落ちます。また、Stream の性質にも影響されます。オートボクシングもパフォーマンスに影響を与えます。たとえば、プリミティブを使用するのであればプリミティブに対応した IntStream のような Stream を使うべきです。
8 スレッドの MacBook Pro で行ったマイクロベンチマークの場合、ArrayList と IntSraem では要素数が多くなればパフォーマンスが向上しましたが、LinkedList ではあまりパフォーマンスが向上しませんでした。
これはマイクロベンチマークなので、すべての場合に当てはまるわけではないのですが、このように Stream のソースによっても大きくパフォーマンスが変わるということだと思います。
最後に分割統治法を行う Spliterator について。Iterator のパラレル版というようなもので、split メソッドが追加されています。ArrayList などだけではなく、HashSet などでも Spliterator を使用することができます。この場合は、Key によって分割を行っていきます。
こういう話はやっぱりおもしろいですね。こういう話を聞けるのが JavaOne の醍醐味です。
CON5091 Java Flight Recorder Behind the Scenes
スピーカは Oracle の Staffan Larsen。
Flight Recorder はトレースとプロファイルを行うツールで、JVM の中に組み込まれています。Java SE 7u40 から正式に使用することができるようになりました。
Flight Recorder でキャプチャできるのは、GC, Synchronization, Compiler, CPU Usage, Exception, I/O などがあります。サンプリングがベースなのでオーバーヘッドも小さく、正確らしいです。
プロファイルもオンデマンドで行うことができ、Mission Control もしくはコマンドラインからプロファイルを開始できます。
Flight Recorder というと、GUI がカッコいいことばかりに目が向きますけど、内部もかなりすごいらしいです。
Flight Recorder を使用可能にするには、Java の起動オプションで -XX:+UnlockCommercialFeatures -XX:+FlightRecorder を指定します。実際に起動するには、起動オプションの -XX:StartFlightRecording=filename=<path>,duration=<time> を指定します。
もしくは jcmd からでも起動できます。
後半は、Flight Recorder の内部構成について。
Compiler や GC などから収集したデータは ThreadLocal のバッファに一時的に収集し、それを Global Buffer に移し、最終的にディスクに保存します。
内部的にはすべての情報はイベントとして保持されます。また、イベントは XML で保持されるようです。
メモリリークを起こさないようにするためにも、収集したデータはずっと保持するのではありません。これにはコンスタントプールを使用して、なるべく使用するメモリを減らすようにしています。たとえば、クラスやメソッド、スレッドはプールします。
おもしろいのがスタックトレースもプールすること。同じスタックトレースであれば、プールしておくということなのでしょうけど、そんなに需要があるんでしょうか?
このセッションは一緒に谷本さんも聴講していたのですが、彼は Flight Recorder 対抗の解析ツールを作っているので、かなり刺激になったようです。確かに、解析ツールについてもうちょっと理解していたら、もっとおもしろかったかもしれません。
Oracle Appliciation Event - MIX
今日のメインイベント。
今年は、Maroon 5 と The Black Keys。
シャトルバスでヒルトンからトレジャーアイランドへ。バスの中ではみなと一緒なのですが、みなライブには興味がなくて、ライブに向かうのはいつも 1 人。でも、今年は北野さんが Maroon 5 の大ファンだということで、2 人でライブへ。
いつものごとく、一般人が入れる一番前に陣取ります。一番前は VIP たちのエリアになっているのもいつも通り。
MC の人が、今日 America's Cup で Oracle Team が優勝したと告げると、観客から USA コールが。
The Black Keys からなのかと思っていたら、いきなり Maroon 5。
Maroon 5 はベテランということもあって、やっぱりステージワークうまいですね。選曲は最新アルバムが一番の多いのですが、デビューのころからのヒット曲はもれなくやってました。ヒット曲入れると盛り上がるんですよね。
北野さんは最近聞き出したらしく、最近のヒットの Moves Like Jagger がお気に入りのようなんですが、私はやっぱり 1st の This Love か Sunday Morning ですね。もちろん、この 3 曲とも演奏してくれました。
そういえば、ボーカルの Adam は歌っている時のバリエーションが少ない。しかもいつも目をつぶってしまっています。写真を撮っているといつも同じような写真になっちゃうんですよね ^ ^;;
Maroon 5 のライブの後、とりあえず食べ物のところへ。そこで、北野さんとはぐれてしまいました。すごい人数だからちょっと目をはなすとすぐに分からなくなってしまいます。
で、続いて The Black Keys。彼らはアルバムは持っているものの、そこまで聞き込んではいませんでした。
The Black Keys って 2 人組なのですが、おもしろいことにギターとドラム。CD だとそれほどでもないのですが、かなり重低音サウンド。それを担っているのが、ドラムの Patrick Carney。なんとダブルバスタム。ダブルバスドラはなんども見たことありますけど、ダブルバスタブははじめて、スネアよりもバスタムの方を多用しているので、重低音のサウンドになっているのでした。
そして、ギターがまた歪んだいい音を出しています。CD だとこれが分からないのですが、ライブだといいですよ、このバンド。
ところで、この 2 人、立ち位置がかなり離れているのです。ギターの Dan Auerbach を撮ろうとすると、ドラムの Patrick Carney がフレームアウトしてしまうのです。
しかも、Dan を撮りやすい位置だと、Patrick はシンバルで顔が見えなくなってしまうのです。で、はじめて一番前ではないところに移動。後半は後ろの方にある階段状のイス席で見たのでした。
ライブが終わったのが 23:30 ぐらい。その後、ゲームのコーナーなどの写真を撮りつつ、まだ残っていた料理を食べたりして過ごしたのですが、ここで痛恨のデジカメのバッテリー切れ。すでに、12 時も過ぎていたので、すごすごと帰りました。
ホテルにもどったのは 1 時過ぎ。明日、起きられるか?