2013/02/08

いろいろプレゼンしてきました

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

JavaOne の後、JavaOne 報告会などのイベントで話をしてきたのですが、忙しさにかまけて喋っただけの状態になってました。いちおう、Slideshare に資料をあげるまではしてあったのですが....

みな、Java SE 8 (含む Project Lambda) と JavaFX の話なので、資料はかなり重複しています。

11/09 JJUG JavaOne 報告会

JavaOne 報告会では Java SE と JavaFX のアップデートについて。

Java SE のアップデートは Java SE 8, Java SE 9, JavaVM, Java SE Embedded の 4 つのトピックについて喋っています。でも、メインはやはり Java SE 8 です。

Java SE 9 については、今回の JavaOne で発表された Project Sumatra について。Sumatra は Java で GPGPU を使うためのプロジェクトです。

現在の状況としては OpenJDK にプロジェクトはできて、イニシャルなソースもコミットされているのですが、当初使うと行っていた OpenCL にかんする部分はまだなし。ほんとにまだできたてという感じですね。

JavaVM はセッションの紹介だけ、そして最後の Java SE Embedded は Compact Profile と、Rasberry Pi の話です。

ところで、私のセッションではいつも何かしらの BGM や効果音を使用しているのですが、どういう曲を使っているのか教えてくれというリクエストがあったので、書いておきます。

  • オープニング: The Beatles "Revolution #1"
  • Java SE 8: The Beatles "Eight Days a Week"
  • Java SE Embedded: Jigsaw "Sky High"
  • エンディング: Michael Hedges "Java Man"

だいたい曲を選ぶのは語呂合わせが多いのです。オープニングの Revolution は、2011 年の JavaOne で Java は Revolution と Evolution が交互に出ているというところから。いちおう、Java SE 8 は Revolution なんですよねww

Java SE 8 の機能紹介で使ったのは単にタイトルに 8 が入っているというだけで、Eight Days a Week です。まぁ、そんなものです。

Java SE Embedded では Compact Profile のベースとなっている Jigsaw から。Jigsaw といえば Sky High ですよね。といっても、こっちの Jigsaw はバンドの名前です。

エンディングの Java Man は、もうそのまま Java Man です。Michael Hedges は大好きなギタリストなので、勝手に Java Man を Java のテーマソングのように使ってます ^ ^;; もちろん、こちらの Java はジャワ島の Java です。

 

さて、次は JavaFX は次の日の JJUG CCC とほとんど同じなので、そちらで紹介します。

もう 1 つ、ちょっと長めの LT で JavaOne に参加するには的な話をしました。でも、資料だけだとぜんぜん意味が分からないと思うので、資料はアップしていません。

もしリクエストがあれば、もうちょっと情報を盛り込んで、公開しようと思います。

 

当日は GREE さんに大きな会場をお借りしたのですが、ちょっと入りが悪かったのが残念なところでした。やはり金曜の午後といいうと参加しにくいですよね。

とはいうものの、ナイトセミナーの 2 時間というのだと時間が足りない。次回はもうちょっと考えて企画したいと思います。

11/10 JJUG CCC 2012 Fall

翌日の土曜日は JJUG CCC

「JavaFX 8.0って何だ!!- JavaFX 最新情報 -」と題して話をする予定だったのですが....

このセッションは Call for Papers で応募したセッションなのですが、応募した時には JavaOne 2013 で JavaFX 8 の話がいっぱい出てくるだろうと思ってこのタイトルにしたわけです。

ところが、JavaOne に行ってみたら、JavaFX 8 の話はほとんどなし ><

話をするはずの櫻庭が JavaFX 8 って何だと聞きたいという状況になってしまっていたのでした。しかたないので、現行バージョンの JavaFX 2.2 の話を中心にして、最後にちょっとだけ JavaFX 8 の話をするという構成にしました。

さて、このプレゼンで使用したのは...

  • オープニング: Otis Redding "(Sittin' on) The Dock of The Bay"
  • JavaFX 2 からの進捗: Ryan Adams "Two"
  • JavaFX 8: Alanis Morissette "Eight Easy Steps"
  • エンディング: Peter, Paul & Mary "San Francisco Bay Blues", Scott McKenzie "San Francisco (Be Sure to Wear Flowers in Your Hair), Eric Burdon "San Francisco Nights"

スライドの写真や BGM にサンフランシスコがいっぱい出てくるのは、JavaFX のコードネームがサンフランシスコの地区や通りの名前になっているからです。

JavaFX 2 が Presidio で、JavaFX 8 が Lombard というコードネームです。Presidio はゴールデンゲートブリッジの根元の部分の地区の名前、Lombard は通りの名前でくねくねした坂道が観光名所にもなっています (資料の 3 ページが Presisio で最後のページが Lombard です)。

ちなみにオープニングの The Dock of The Bay はタイトルにはサンフランシスコは入っていないものの、歌の場面は San Francisco なのでした。

JavaFX 2 が Two で JavaFX 8 が Eight Easy Steps なのは、単に語呂合わせです ^ ^;;

11/17 札幌 Java カンファレンス

CCC の次の週は札幌 Java カンファレンスへ。

札幌 Java カンファレンスでは「Lambda への道」と「What's up JavaFX!」と題してプレゼンを行ないました。

Lambda への道は、JJUG の JavaOne 報告会の Project Lambda の部分を増補改訂したものです。

JavaOne 報告会の時は、Project Lambda の背景についてぜんぜん話をしなかったのですが、ここは非常に重要だと思っているので、Lambda への道ではそこを説明するようにしています。

後は Stream のあたりを追加しています。

さて、ここで使用した曲は...

  • オープニング: Joni Mitchell "The Circle Game"
  • Lambda の文法: Edie Brickell & New Bohemians "The Wheel"
  • API: Daniel Powter "Free Loop"
  • エンディング: Aerosmith "Full Circle"

すぐみて分かると思いますが、すべて円とか輪などに関連した曲です。もちろん、ループにかけてあるわけです。

もう 1 つの What's up JavaFX! はやはり JavaOne 報告会の資料を使い回し。でも、それが失敗でした。

JavaOne 報告会の資料では、JavaFX の基本についての部分は少しで、後は JavaFX 2.2 の新機能を紹介するという形になっています。

しかし、JavaFX をよく分かっていない人が聞いたら、JavaFX 2.2 の新機能の部分だけを聞いてもきょとんとしてしまうわけです。ひさびさに大失敗してしまったプレゼンでした。ほんと聴講されていたみなさま、ごめんなさい。

これというのも、誰に聞いてもらうかというターゲットをしっかり決めておかなかったせいだと思っています。

東京の JavaOne 報告会は平日の昼間に開催して、それに参加される方というのは、モチベーションも高く、よく分かっている方たちだと思います。

しかし、札幌では週末開催ということもありますし、初心者の方も多かったのではないかと思うわけです。そういう参加者の違いを無視して、同じ資料で話をすることは、やはり無理があったのだと思います。ほんと、ごめんなさい。

11/30 第 8 回 JavaFX 勉強会

11 月の最後は 第 8 回 JavaFX 勉強会。わざわざこんな忙しい時にやらなくてもいいのですが、会場がたまたまあいていたので、ちょっと早い忘年会も合わせて開催したわけです。

この時は Catch Up JavaFX 2.2 & Scene Builder 1.1 と題してプレゼンをしました。

JavaFX 勉強会に参加されている方たちは、ある程度知っている方が多いので、JavaFX の基礎の部分は少なめで、それよりは JavaFX 2.2 の機能を紹介する方に時間を割きました。

Scene Builder 1.1 は CSS Analyzer を中心に説明しましたが、まぁおまけみたいなものです。

使っている曲は JavaOne 報告会の時と同じです。

12/01 関西 Java エンジニアの会スペシャル! JavaOne 2012 San Francisco 報告会

JavaFX 勉強会の次の日は、大阪へ。関ジャバの JavaOne 報告会です。

Togetter: 関西Javaエンジニアの会スペシャル! JavaOne 2012

関ジャバでは Lambda への道と、Introducing JavaFX 2 の 2 本立て。Lambda への道は北海道と同じものです。JavaFX の方は初心者向けにして JavaFX 2 の紹介と、JavaOne での話題という形にしました。

このプレゼンも使っている曲は同じです。

懇親会の後、流れ解散になってしまったのですが、irof さんたちが Lambda のセッションに触発されてコードを書きにいっていたらしいです。こういうのを聞くと、ほんとプレゼンやっていてよかったなぁと思いますね。

1/19 オープンセミナー広島 2013

年が変わって最初のプレゼンはオープンセミナー広島 (OSH)でした。

90 分枠で、What's New about Java SE 8 というタイトルでの発表でした。

半分ぐらいを Project Lambda、1/4 を JavaFX、残りの 1/4 を Nashorn や Date & Time API などについて話をしました。

とはいっても、Lambda への道と Introducing JavaFX 2 とかなりの部分がダブってます。

さて、使っている曲です。資料の使い回しをしていることから分かるとは思いますが、あまり代わりばえないです。

  • オープニング: The Beatles "Eight Days a Week"
  • イテレータ: Edie Brickell & New Bohemians "The Wheel"
  • Lambda API: Daniel Powter "Free Loop"
  • Lambda まとめ: Aerosmith "Full Circle"
  • Java SE Embedded: Jigsaw "Sky High"
  • エンディング: Michael Hedges "Java Man"

OSH は Java だけでなく、PHP や VisualStdio などいろいろ。それもあって、会場は立ち見も出るほどで、かなり盛況でした。

1/26 JavaOne 2012 San Francisco 報告会 in 富山

広島の翌週は富山へ。

まさに吹雪のど真ん中でした。25 日に富山入りしようとしていたのですが、飛行機の富山便はのきなみ欠航。私が乗ろうとしていた 18:20 の便も結局欠航。幸いにも小松便は飛んでいたので、小松便の最終便に振り替えてもらって、そこから電車で富山へ。富山に到着したのは 26 日になってからでした。

さて、JavaOne 報告会での櫻庭の担当分は JavaOne のフォトセッションと Java SE (含む JavaFX) でした。とはいうものの、もう JavaOne が開催されてからかなりたつので JavaOne のトピックというよりは Java SE 8 について。

資料は広島のものを 60 分用に再構成したものです。

残念ながら参加者が少なかったのですが、その分、脱線ありでなかなかおもしろかったです。特に太一と Lambda について議論できたのはよかったです。最終的な結論は invokeDynamic は使うのはむちゃくちゃ難しいけど、とても強力ということ。

結局、大幅に時間を超過して、午前中は私のプレゼンだけになってしまいました ^ ^;;

1/31 JJUG & html5j.org ナイトセミナ Java ♡ HTML5 Night

先月末は JJUG と html5j.org の共催で Java ♡ HTML5 Night。このセミナは人気があって、Oracle 青山のセミナールームを 4 部屋ぶち抜き。ただ、歩留まりはちょっと低かったかも。

私は HTML 5 in JavaFX と題して、JavaFX に組み込みのブラウザについてショートプレゼン。

最近、プレゼンの資料環境は Java SE 8 に移行しているので、使用している JavaFX も JavaFX 8 に移行しています。

JavaFX 2.x の HTML 5 対応はかなりイマイチだったのですが、JavaFX 8 になってずいぶん改善されました。これは予想していなかったので、かなりビックリでした。

JavaFX 2.x の WebView だと見られなかった Web ページが、JavaFX 8 だと見られるというのが多くありました。プレゼンの中で HTML 5 Test を実行してみたのですが、スコアが 348。

Chrome にはまったく太刀打ちできませんが、IE10 のスコアよりも高く、Firefox 18 よりは低いぐらい。なかなか健闘していると思いませんか。

というわけで、プレゼンの記録でした。

プレゼンのソースを公開しました

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

資料ではなくてソースです。

みなさん、ご存じの通り、櫻庭はいつも JavaFX でプレゼン資料を作成しています。そして、そのためのフレームワークもあります。しかし、普通の人にはちょっと使いづらいのは分かっていたので、今のフレームワークの上にもう 1 段レイヤーを作って簡単に使えるようにできたら公開しようと思っていました。

でも、いつまでたってもモチベーションがあがらず、そのせいでなかなか時間もとれずじまいで、放置していたわけです。自分でもプレゼンフレームワークはプレゼンの時しかつかわず、そういう時はだいたい切羽詰まっているので、フレームワークの改良まで手が回らないという状況でした。

しかし、このままだと、永遠に公開しなくなってしまいそうだったので、広島で使ったコンテンツも一緒にして、そのまま公開してしまうことにしてしまいました。

GitHub: whatsnewaboutjavase8

NetBeans のプロジェクトなので、クローンして、NB の「デフォルトの JavaFX プラットフォーム」を設定し直せば、動くはずです。

起動したら画面をクリックしていけば、進みます。

コンテンツは Illustrator で作成し、SVG に変換します。そして、JavaFX ではその SVG を読み込んで表示しています。

基本的な動き方は JavaFX in the BoxJavaFX でプレゼンツールに書いたものと同じです。もうちょっと詳しいことは JavaFX in the Box の方に書こうと思っています。

2012/12/16

大都会岡山 Advent Calendar 16 日目 - 岡山といえばパフェだよね

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

このエントリは 大都会岡山 Advent Calendar 2012 の第 16 日目のエントリーです。

昨日は @razon さんの ウェルカム・トゥ・オクトプレス で、明日は Masakatsu Kodani さんです。

さて、東京に住む櫻庭にとって岡山というと、やはり後楽園とか倉敷の町並みとかを思い浮かべるわけです。ところが、大都会岡山はフルーツパフェの街でもあるのです!!!!

ということで、櫻庭が岡山で食べたパフェを紹介しようと思います。といっても、岡山を訪れたことは 2 回しかないので、4 つのパフェしか食べてないのですが ^ ^;;

カフェレストランオリビエ

はじめは JR 西日本が運営しているホテルグランヴィアのカフェのオリビエです。

岡山駅に直結なので、便利ですね。

ここで食べたのがイチゴとライチのパフェのリュネル。なかなか豪華です。

_DSC8579

_DSC8582

_DSC8606

_DSC8539

_DSC8570

関連ランキング:カフェ | 岡山駅前駅岡山駅西川緑道公園駅

Fruits-J

天満屋の地下にあるジューススタンドの Fruits-J でもパフェが食べられます。

パフェはちょっと安っぽいのですが、ジューススタンドなのでしかたないですね。

_DSC8311

_DSC8300

_DSC8317

関連ランキング:フルーツパーラー | 県庁通り駅郵便局前駅田町駅

Signe

岡山駅の地下街の岡山一番街にあるカフェの Signe。店の作りがちょっと不思議な感じですが、内装はモダンです。

ここはスイーツの種類はそれほど多くはないのですが、パフェは 2 種類。苺とガトーショコラのパフェを食べました。

_DSC9017

_DSC9085

_DSC9080

_DSC9021

_DSC9059

関連ランキング:カフェ | 岡山駅前駅岡山駅西川緑道公園駅

三宅商店

三宅商店は倉敷のカフェで、マスキングテープでも有名なところ。古民家をそのまま使った内装はなかなか風情があります。

今時、エアコンがないというのもすごいのですが、でもこの建物にはエアコンは似合わないので、いいかも。

櫻庭が食べたのは春の苺パフェです。

_DSC8898

_DSC8976

_DSC8867

_DSC8968

_DSC8878

_DSC8928

_DSC8945

関連ランキング:カフェ | 倉敷市駅倉敷駅

まだまだいったことがない店がいっぱいあるので、次にいった時はまた新しいパフェを開拓したいと思っています!!

2012/12/01

Java Advent Calendar 1 日目 - Project Lambda の遅延評価

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

このエントリは Java Advent Calendar 2012 の第 1 日目です。

去年の Java Advent Calendar も第 1 日目を書いて、しかも Project Lambda についてでした。

今年も Project Lambda について書くわけですが、去年とはちょっと観点を変えようと思います。

今年の JavaOne で Java SE の一番のトピックといえば、やっぱり Project Lambda だったと思います。実際、Keynote でも Brian Goetz が登壇して Lambda の説明をしていますし、セッションも Lambda だけで 5 つもあったほどです。

実際に Brian Goetz の Lambda のセッションに出て思ったのは、Lambda の言語仕様はほぼ固まったということです。そして、開発の中心は Lambda の実装方法や、Lambda を使った API の方に移ってきています。

今年は櫻庭も JJUG で Project Lambda のハンズオンを行なったのですが、Project Lambda を使いこなすのは、やはり Lambda に対応した API を使いこなすことにあると感じました。

でも、その API についてはほとんど触れません。いちおう、ハンズオンから変化したことをあげておきます。

  • インタフェースのデフォルトメソッドの記述が変更
  • Stream インタフェースの導入
  • パラレル処理の実装

現在公開されている build 64 ではデフォルトメソッドの記述はまだ変更されていないのですが、Lambda の Mercurial ではすでに記述法が変更されています。

具体的には default の書く位置が変更になりました。

    public interface Foo {
        void foo() default { .... }
    }

         | 変更
         V

    public interface Foo {
        default void foo() { .... }
    }

もう一方の Stream インタフェースが Lambda の API の中心になるインタフェースです。今までは filter メソッドや map メソッドなどは Iterable インタフェースで定義されていたのですが、これらはみな Stream インタフェースで定義されるようになりました。

Iterable インタフェースに残っているのは forEach メソッドぐらいです。

Stream オブジェクトを取得するには Streamable インタフェースの stream メソッドを使用します。てっきり、Iterable インタフェースに定義されるのかと思ったら、新たにインタフェースが導入されていたので、ちょっと意外でした。

Streamable インタフェースのサブインタフェースとして Collection インタフェースや Queue インタフェースなどがあります。

ハンズオンの時は、パラレル処理は Array に対してしか実装されていなかったのですが、本格的に実装が行なわれています。


さて、今日の本題は Stream インタフェースです。

といっても Stream インタフェースの使い方ではありません。ではなくて、Stream インタフェースの実装についてです。

というのも、Stream インタフェースで提供されているメソッドは遅延評価されるからなのです。これは Scala の Stream と同じですね。

Java で遅延評価というのはあまり例がないと思うので、どうやって実装されているか調べて見たよというのが、この blog エントリなわけです。

だから、Lambda 式についてはまったく解説しませんww Lambda 式については、ハンズオンの資料を見てください。

遅延評価

注) コメント id:bleis-tift さんに指摘いただきましたが、ここでいっている遅延評価は正しくは遅延計算と呼ぶべきものです。この後の遅延評価と書かれている部分は遅延計算と読み直してください。とりえあず、このエントリではそのままにしておきますが、今後は安易に遅延評価という言葉を使用しないようにしようと思います。

例題として、整数のリストから偶数を取り出して標準出力に出力することを考えてみましょう。

Lambda 式と Stream インタフェースを使うと次のように書けます。

        List<Integer> nums = Arrays.asList(0, 1, 2, 3, 4, 5);

        // Stream オブジェクトの取得
        Stream<Integer> stream = nums.stream(); 

        // 偶数をフィルタリングしたStreamオブジェクトを生成
        Stream<Integer> stream2 = stream.filter(s -> s%2 == 0);

        // 標準出力に出力
        stream2.forEach(s -> System.out.println(s));

これは内部イテレータで書いているわけですが、あえて外部イテレータで書き直してみました。

        List<Integer> nums = Arrays.asList(0, 1, 2, 3, 4, 5);

        List<Integer> nums2 = new ArrayList<>();
        for (Integer s: nums) {
            if (s%2 == 0) {
                nums2.add(s);
            }
        }

        for (Integer s: nums2) {
            System.out.println(s);
        }

するとループが 2 回になってしまうわけです。こんなことをするぐらいだったら、下のように 1 回のループで書けばいいわけです。

        List<Integer> nums = Arrays.asList(0, 1, 2, 3, 4, 5);

        for (Integer s: nums) {
            if (s%2 == 0) {
                System.out.println(s);
            }
        }

でも、内部イテレータで書くのは、処理が独立に記述できることや、処理順序をイテレータに任せられるとか、パラレル処理にしやすいとか、いろいろと利点があるわけです。

とはいうものの、filter メソッドや map メソッドのようなバルクオペレーションを連ねてしまうと、どんどんループが増えていってしまいます。ループが増えるということはパフォーマンスが落ちるということです。

これじゃ、せっかくバルクオペレーションで書けたとしても、魅力半減です。

そこで登場するのが、遅延評価です。

遅延評価は変数を実際に使用する時に、変数を評価することですが、いまいち意味が分かりません。

先ほどのコードで考えてみましょう。遅延評価を行うことで filter メソッドでは、実際にはループを行っていません。

ループを行うのは forEach メソッドだけになります。

        List<Integer> nums = Arrays.asList(0, 1, 2, 3, 4, 5);

        // Stream オブジェクトの取得
        Stream<Integer> stream = nums.stream(); 

        // ループしない。遅延評価の対象
        Stream<Integer> stream2 = stream.filter(s -> s%2 == 0);

        // ループする。
        // s を出力するときにフィルタリングされるかどうかを評価する
        // s がフィルタリングされるのであれば、出力しない
        stream2.forEach(s -> System.out.println(s));

変数を使うときというのは、この場合 forEach メソッドで変数 s を出力するときになります。そこで forEach のループの時に、遡ってフィルタリングの処理も行われるのです。

この結果、遅延評価を行うことで、ループが 1 回で処理が完了することになります。

また、このことから、Stream インタフェースで定義しているすべてのメソッドが遅延評価を行うわけではないことも分かります。

では、どのメソッドが遅延評価され、どのメソッドが即時評価されるのでしょうか。

残念ながら、Stream インタフェースの Javadoc を見ただけでは、どれが遅延評価されるのか分かりません。なので、ソースを読んでチェックしてみました。遅延評価をされる主なメソッドを以下に示します。

  • concat
  • cumulate
  • filter
  • flatMap
  • limit
  • map
  • skip
  • sorted
  • sequential
  • tee
  • uniqueElement
  • unordered

逆に遅延評価されずに即時評価される主なメソッドも列挙しておきます。

  • allMatch
  • anyMatch
  • findAny
  • findFirst
  • fold
  • forEach
  • groupBy
  • noneMatch
  • reduce
  • reduceBy
  • toArray

基本的には戻り値が Stream インタフェースのメソッドが遅延評価されると覚えておけば大丈夫です。

遅延評価の実装

では遅延評価をどのように実装するのでしょうか。

とりあえず、Project Lambda の API のクラス構成から見ていきましょう。なお、Project Lambda で追加される API は、バルクオペレーション API (Bulk Operation API)と呼ばれているので、ここでもそう呼ぶことにします。

まずは、filter メソッドや map メソッドの引数として Lambda 式で記述されるインタフェースです。これらのインタフェースは、java.uitl.funtions パッケージに定義されています。

主なものをあげると

  • Block
  • Combiner
  • BinaryOperator
  • Mapper
  • Predicate

などがあります。たとえば、Block インタフェースは forEach メソッドの引数として使われます。

これに対し、これらのインタフェースで記述した処理を実行するクラス群が java.util.streams パッケージで定義されています。

Stream インタフェースも java.util.streams パッケージで提供されています。

Stream インタフェースを実装しているコンクリートが ValuePipeline クラスです。ValuePipeline クラスのスーパークラスは AbstractPipeline クラスなのですが、こちらは Stream インタフェースを実装していません。

また、Stream オブジェクトを生成するなどのユーティリティメソッドを定義しているのが Streams クラスです。

Streamable インタフェースのサブインタフェースの Collection インタフェースや Queue インタフェースが Streams クラスを使用して Stream オブジェクトを取得しています。

他のクラスは追々説明していきましょう。

 

さて、コードを追っていくとしても、やみくもに追っていってもしかたありません。そこで、次のコードの処理を見ていこうと思います。

       List<Integer> nums = Arrays.asList(0, 1, 2, 3, 4, 5, 6);

        Stream<Integer> stream1 = nums.stream();
        Stream<Integer> stream2 = stream1.filter(s -> s%2 == 0);
        Stream<Double> stream3 = stream2.map(s -> s/2.0);
        stream3.forEach(s -> System.out.println(s));

filter メソッドと map メソッドという 2 つの遅延評価が行われるメソッドがあり、最後に即時評価が行われる forEach メソッドがあるというコードです。

Streamable#stream メソッド

まずは stream メソッドです。stream メソッドは Streamable インタフェースで定義されています。

Streamable インタフェースのサブインタフェースとして、Collection インタフェースなどがあります。Collection インタフェースのサブインタフェースにはここでも使用している List インタフェースや Set インタフェース、Queue インタフェースなどがあるので、これらのクラスはバルクオペレーションが可能です。

stream メソッドの実装はコンクリートクラスではなく、デフォルトメソッドを使用して Collection インタフェースに記述されています。

    Stream<E> stream() default {
        return Streams.stream(this, StreamOpFlags.IS_SIZED);
    }

前述したように、今公開されているビルドは default を書く位置が違うので注意してください。

stream メソッドは単に Streams.stream メソッドをコールしているだけでした。Streams.stream メソッドはオーバーロードされているのですが、第 1 引数が T で、T が T extends Sized & Iterable<U> の stream メソッドがコールされます。

Sized インタフェースも Project Lambda で導入されたインタフェースで、サイズが決まっているコレクションをあらわしています。

    public static<U, T extends Sized & Iterable<U>> Stream<U> stream(T entity, int flags) {
        return new ValuePipeline<>(new Spliterator.Sequential<U>() {
            @Override
            public Iterator<U> iterator() {
                return entity.iterator();
            }

            @Override
            public void forEach(Block<? super U> block) {
                entity.forEach(block);
            }

            @Override
            public int getSizeIfKnown() {
                return entity.size();
            }
        }, StreamOpFlags.IS_SIZED | flags);
    }

Streams クラスの stream メソッドでは ValuePipeline オブジェクトを生成して、返しています。前述したように、ValuePipeline クラスは Stream インタフェースの実装クラスになっています。

そして、ValuePipeline クラスのコンストラクタはスーパークラスの AbstractPipeline クラスのコンストラクタをコールしています。

    protected final AbstractPipeline<?, E_IN> upstream;
    protected final IntermediateOp<E_IN, E_OUT> op;
    protected final Spliterator<?> spliterator;
    protected final int depth;
    protected final int sourceFlags;
    protected final StreamShape shape;

    private Iterator<E_OUT> iterator;

    protected AbstractPipeline(Spliterator<?> spliterator, int sourceFlags, StreamShape shape) {
        this.upstream = null;
        this.op = null;
        this.spliterator = Objects.requireNonNull(spliterator);
        this.depth = 0;
        this.sourceFlags = sourceFlags;
        this.shape = shape;
    }

ここで注目しておいて欲しいのが、upstream というフィールドがあることです。upstream フィールドの型は AbstractPipeline クラスです。つまり、リスト構造的に AbstractPipeline オブジェクトが連なっていくことができるということです。

Stream#filter メソッド, Stream#map メソッド

では、次に filter メソッドと map メソッドです。この 2 つのメソッドは実質的にはほとんど変わりません。

filter メソッドと map メソッドを実装しているのは ValuePipeline クラスです。

    @Override
    public Stream<U> filter(Predicate<? super U> predicate) {
        return chainValue(new FilterOp<>(predicate));
    }

    @Override
    public <R> Stream<R> map(Mapper<? extends R, ? super U> mapper) {
        return chainValue(new MapOp<>(mapper));
    }

この chainValue メソッドをコールしているメソッドが遅延評価の対象になります。chainValue メソッドは AbstractPipeline クラスで実装されています。

    protected<E_NEXT> Stream<E_NEXT> chainValue(IntermediateOp<E_OUT, E_NEXT> op) {
        return new ValuePipeline<>(this, op);
    }

なんと、ValuePipeline オブジェクトを生成しているだけです。ただし、先ほどの ValuePipeline オブジェクトの生成とはコンストラクタの引数が違います。

    public ValuePipeline(AbstractPipeline<?, T> upstream, IntermediateOp<T, U> op) {
        super(upstream, op);
    }

第 1 引数が upstream という変数名になっています。ということは...

    protected AbstractPipeline(AbstractPipeline<?, E_IN> upstream, IntermediateOp<E_IN, E_OUT> op) {
        this.upstream = Objects.requireNonNull(upstream);
        this.op = Objects.requireNonNull(op);
        this.spliterator = upstream.spliterator;
        this.depth = upstream.depth + 1;
        this.sourceFlags = upstream.sourceFlags;
        this.shape = upstream.shape;
        assert upstream.getShape() == op.inputShape();
        assert (upstream.depth == 0) ^ (upstream.op != null);
    }

やはり AbstractPipeline オブジェクトの upstream フィールドに代入されています。先ほどの指摘したように、Stream オブジェクトがこのようにして、リスト構造的に津ならなっていくわけです。

もう 1 つ、spliterator フィールドに upstream フィールドの spliterator フィールドが代入されています。

とすると、遅延評価のメソッドをいくつ連ねても、spliterator フィールドは一番始めの stream オブジェクトを作った時の spliterator フィールドが参照されるということになります。

Stream#forEach メソッド

最後に forEach メソッドです。ValuePipeline クラスの forEach メソッドを次に示します。

    public void forEach(Block<? super U> block) {
        pipeline(ForEachOp.make(block));
    }

filter メソッドや、map メソッドは、実際に処理を行なうオブジェクトをラップするクラスのオブジェクトを生成していましたが、 forEach メソッドでは ForEachOp オブジェクトの生成ではなく、make メソッドをコールしています。

最後に Op がつくクラスは java.util.streams.op パッケージで定義されています。

    private final TerminalSink<T, Void> sink;
    private final StreamShape shape;

    protected ForEachOp(TerminalSink<T, Void> sink, StreamShape shape) {
        this.shape = Objects.requireNonNull(shape);
        this.sink = Objects.requireNonNull(sink);
    }

    public static<T> ForEachOp<T> make(final Block<? super T> block) {
        Objects.requireNonNull(block);
        return new ForEachOp<>(new TerminalSink<T, Void>() {
            @Override
            public void accept(T t) {
                block.apply(t);
            }

            @Override
            public Void getAndClearState() {
                return null;
            }
        }, StreamShape.VALUE);
    }

ForEachOp クラスの make メソッドを見てみると、結果的には ForEachOp オブジェクトを生成していることが分かります。この時に TerminalSink オブジェクトもいっしょに生成していることが分かります。

そして、先ほどの forEach メソッドに戻って、pipeline メソッドをコールしていることが分かります。

    public<R> R pipeline(TerminalOp<E_OUT, R> terminal) {
        assert getShape() == terminal.inputShape();
        return evaluate(terminal);
    }
 
    protected<R> R evaluate(TerminalOp<E_OUT, R> terminal) {
        // @@@ NYI If the source size estimate is small, don't bother going parallel
        if (StreamOpFlags.PARALLEL.isKnown(sourceFlags)) {
            return evaluateParallel(terminal);
        }
        else
            return evaluateSequential(terminal);
    }

はじめの assert 文はともかく、evaluate メソッドをコールしていることが分かります。なんとなく、それっぽいですね。

そして、evaluate メソッドではパラレルに処理するかどうかで処理を切り替えています。ここではシリアルに処理する方を見ていきましょう。

    protected <R> R evaluateSequential(TerminalOp<E_OUT, R> terminal) {
        return (R) terminal.evaluateSequential(new SequentialImplPipelineHelperSource());
    }

SequentialImplePipelineHelperSource クラスがなんなのかはとりあえずおいておいて、terminal の evaluateSequential メソッドをコールしていることが分かります。

terminal の型は TerminalOp インタフェースですが、ここでの実装クラスは ForEachOp クラスです。

    public <S> Void evaluateSequential(PipelineHelper<S, T> helper) {
        return helper.into(sink).getAndClearState();
    }

先ほどおいておいた SequentialImplePipelineHelperSource クラスの into メソッドをコールしているのでした。into メソッドの引数の sink は、先ほど ForEachOp クラスの make メソッドの中で作成した無名クラスのオブジェクトです。

SequentialImplePipelineHelperSource クラスは AbstractPipeline クラスの内部クラスになり、into メソッドを定義しているのはスーパークラスの SequentialImplePipelineHelper クラスです。で、それを見てみると、今度はさらにスーパークラスの AbstractPipelineHelper クラスの into メソッドがコールされていることが分かります。

    public <S extends Sink<P_OUT>> S into(S sink) {
            Sink<P_IN> wrappedSink = wrapSink(sink);
            wrappedSink.begin(spliterator.getSizeIfKnown());
            spliterator.forEach(wrappedSink);
            wrappedSink.end();
            return sink;
        }

        @Override
        public Sink<P_IN> wrapSink(Sink sink) {
            Objects.requireNonNull(sink);

            for (int i = upTo - 1; i >= from; i--) {
                sink = ops[i].wrapSink(
                        StreamOpFlags.combineStreamFlags(sourceFlags, opsFlags[i]),
                        sink);
            }
            return sink;
        }

いろいろと処理は行なわれていますが、重要なのは赤字の部分。つまり、spliterator の forEach メソッドをコールしていることが分かります。

この forEach メソッドでやっとループになります。

spliterator が、連なっている Stream オブジェクトのはじめの Stream オブジェクトに定義されているものだということを思いだしてください。

forEach メソッドでは Block インタフェースの apply メソッドをコールします。しかし、ここでは Sink クラスでラップしてあり、コールされるのは spliterator を定義した Stream オブジェクトの op フィールドの accept メソッドがコールされます。ここではそれがなんだったかというと、FilterOp クラスになるわけです。

FilterOp クラスの wrapSink メソッドを次に示します。

    public Sink wrapSink(int flags, final Sink sink) {
        Objects.requireNonNull(sink);
        return new Sink.ChainedValue(sink) {
            @Override
            public void accept(T t) {
                if (predicate.test(t))
                    downstream.accept(t);
            }
        };
    }

ようやく、filter メソッドの処理が出てきました。filter メソッドの引数は Predicate インタフェースのオブジェクトになり、Predicate インタフェースは test メソッドが定義されています。

この test メソッドがコールされるのが赤字の部分です。test メソッドの戻り値が true の場合、言いかえればフィルターされた結果で残る場合は downstream 変数が示している次の処理の accept メソッドをコールします。

こうすることで連なっている処理を行なっていくわけです。

同様に MapOp クラスの wrapSink メソッドを見てみましょう。

    public Sink<t> wrapSink(int flags, Sink sink) {
        return new Sink.ChainedValue<t>(sink) {
            @Override
            public void accept(T t) {
                downstream.accept(mapper.map(t));
            }
        };
    }

Stream インタフェースの map メソッドの引数の型は Mapper インタフェースになります。Mapper インタフェースも map メソッドを定義しており、この部分が Lambda 式で評価されるわけです。それが赤字で書いた map メソッドのコールになります。

map メソッドで 1 つの要素を他の型に変換するので、その後、再び連なる処理の accept メソッドをコールするというわけです。

このように Stream オブジェクトの連なりから、処理をつなげていくことで、ループが 1 回だけで処理が可能になっているわけです。

最後はちょっとはしょってしまいましたが、遅延評価の手法についてコードをおっていきました。遅延評価というだけであれば簡単ですけど、実装はなかなか大変そうです。

明日は @btnrouge さんです!

2012/10/04

JavaOne 2012 Last Day

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

JavaOne もとうとう最終日です。今日は朝から Community Keynote。ただし、いつもよりはちょっと遅くて、9 時の開始。

去年は最終日は寝坊してしまったわけですが、今年は起きました!! でも、眠い。

初日の Keynote とは違って、今日の Keynote は Hilton。でも、例年 Keynote をやっている Grand Ballroom ではなく、Imperial Ballroom でした。

やっぱり、今年は参加者数が少ないのかなぁ。

ところで、こうやっていろいろと JavaOne/OOW の写真を撮っているわけですが、実をいうと去年まで写真撮影はほんとは禁じられていたんです。誰も守ってなかったですけどww Oracle が固いからというわけではなくて、Sun の頃からずっと撮影は禁止だったんです。

ところが、今年から写真撮影 OK になりました!! 撮影していいよと書いてあるのが、上の写真。ということで、今年から堂々と写真を撮ることができたのでした。

さて、今日聴講したセッションです。

Facebook に書いたノート

Java SE 8 で JMX が 2.0 にアップデートされるので、新しい情報でもあるかと思って、JMX のセッションに出たのですが...ぜんぜん新しいことがなくて、JMX のチュートリアル的なセッションだったので、がっかりでした。

Keynote

Community Keynote
_DSC3099

今日の Keynote はコミュニティが主題。でも、コミュニティといってもユーザのコミュニティもあれば、ベンダーのコミュニティもあるわけです。

ということで、ベンダーのパネルと、ユーザーグループのパネル。

パネルでおもしろかったのが、Cloudera の Mike Olson がいったこと。Mike はスーツだったのですが (といってもノーネクタイですけど)、こんなのを着てきてしまったオレがバカだったと。

JavaOne の正装はジーンズに T シャツですからね。実際、パネルの登壇者もみんなジーンズ。スーツ姿が多い OpenWorld とはぜんぜん違いますww

パネルの前に OpenJDK の注目プロジェクトということで、Project Sumatra のデモがありました。また、パネルの後には 2 つの事例紹介。いずれも Duke's Choice Awards の受賞者 (社) です。

1 つ目が先ほどのベンダーパネルにも出ていた Perrone Robotics の Paul Perrone による自律動作が可能なロボットカーである Rumbles の紹介。

Rumbles はセンサーを使って障害物にぶつからないように自走します。でも、後ろ側にはセンサーがついていないらしく、バックでステージの奥に走り始めたら、すかさず落ちないように Paul が支えてやってました.。

そして、もう 1 つの事例が Liquid Robotics の自律動作する海洋調査ロボットの紹介。Liquid Robotics といえば、Java の父 James Gosling が所属しているところでもあります。

で、登場したんですよ James が。もうそれだけで、会場は盛り上がる!

でも、James は久しぶりにこういう場所で喋るのためか、一段とスピーチがヘタになってましたねww まぁ、James がしゃべりがうまいとかどうかというより、そこにいるという方が重要なのです。

最後に Sharat Chander、Georges Saab と一緒に T シャツ投げ!!

James は Keynote が終わっても、ずっと取り囲まれていて、写真やサインをせがまれていました。やっぱり、James Gosling の人気は衰えず。

これが今年の JavaOne の一番のサプライズでした。


_DSC3096

_DSC3079

ステージ横には見慣れぬマシンが

_DSC3089

Sharat と寺田さん。写真を撮っているのは James Weaver!

_DSC3125

今日の MC は Shart Chander

_DSC3137

JavaOne のバッジにはスピーカーやらなにやらいろいろと貼られるのですが、Shart のバッジはこんなにたくさん!

_DSC3160

Donald Smith にバトンタッチ

_DSC3183

_DSC3195

Sumatra の紹介。右にいるのは AMD の Gary Frost

_DSC3203

_DSC3218

Sumatra でマンデルブロー

_DSC3227

こんな感じに書きます

_DSC3239

物理シミュレーションのデモ

_DSC3245

よく見たらパーティクルが Duke!

_DSC3263

ベンダーのパネル
_DSC3269

_DSC3280

Eucalyptus Systems の Marten Mickos

_DSC3294

Twitter の Chris Aniszczyk

_DSC3298

Cloudera の Mike Olson

_DSC3325

Eclipse の Mike Milinkovich

_DSC3342

Perrone Robotics の Paul Perrone

_DSC3356

_DSC3372

Georges Saab

_DSC3395

招き入れたのが London Java Community の Martijn Verburg
_DSC3436

そして再びパネル

_DSC3459

LJC の Ben Evans

_DSC3481

Stackthread の James Gough

_DSC3488

jClarity の Richard Warburton

_DSC3508

Oracle の Cecilia Borg

_DSC3522

SOUJava の Bruno Souza

_DSC3551

_DSC3561

Perrone Robotics の自走車登場

_DSC3600

_DSC3578

_DSC3597


落ちそうになるのを食い止める
_DSC3634

_DSC3650

御大 James Gosling 登場

_DSC3675

_DSC3748

袋から取り出したのは T シャツ!

_DSC3749

もちろん投げます

_DSC3751

_DSC3768

_DSC3769

_DSC3770

_DSC3788

Steve Chin 登場

_DSC3813

Nighthacking Tour と題してヨーロッパを回るらしい

_DSC3816

_DSC3822

取り囲まれる James
_DSC3839

Technical Session

CON6375 Custom Charts - Simon Ritter
_DSC3869

Facebook に書いたメモ

JavaFX ではチャート (グラフ) が使えるようになったのですが、チャートをカスタマイズする話。

Custom Control のセッションと同じように、まずは CSS で見ばえを変化させるところから。というか、チャートは CSS だけで見た目を変化させる項目がいっぱいなので、CSS を使わざるを得ないのですが。

たとえば、凡例をチャートの左側に表示するのであれば、-fx-legend-visible: true と -fx-legend-side: left を指定します。

これ以外にも多くの設定項目があります。

続いて、既存のチャートのクラスをベースに拡張する方法。例としてマウスクリックするとその部分が少しだけ離れるというパイチャートを作ります。

クリックした領域から Arc オブジェクトを取得し、アニメーションで外側に移動させます。全部のコードを示しているわけではないので、不明部分もあるのですが、なんとなく雰囲気が分かります。

しかし、手順の中に deprecated なメソッドを使うとあるんですけど、いいんでしょうかww

それにしても、このサンプルを公開してくれないかなぁ...

おまけ

_DSC3852

今日、はじめて朝ご飯に遭遇しました!! Keynote の会場を出たら朝ご飯があったのです。

Keynote が押して、次のセッションの開始時間が迫ってきていたのですが、腹が減ってはいくさができぬということで、朝から甘いドーナツを食べたのでしたww

で、セッションに遅刻しました ><

ということで、今年の JavaOne も終了。来年は 9 月 22 日から 26 日まで。何でもいいんですけど、期末はやめてもらいたいなぁ....