Furyu
[フリュー公式]

Tech Blog

フリュー株式会社の技術ブログです

2019年12月6日

kakuda.takumi

JJUG CCC 2019 Fallに参加&登壇してきました!!

こんにちは。ピクトリンク事業部の角田です。
2019年11月23日(土)に開催されましたJavaのカンファレンスであるJJUG CCC 2019 Fallに参加&登壇してきましたので報告させていただきます。
弊社はこちらのカンファレンスのゴールドスポンサーをさせていただき、スポンサーセッションという枠で登壇もさせていただいておりました。

JJUG CCCとは?

公式サイトより引用

JJUG CCCは毎年2回、春と秋に開催する日本最大のJavaコミュニティイベントです。
Java関連の技術や事例に関する良質なセッションが行われ、また異なる分野で活躍するJava技術者が一堂に会する場ともなっています。

Javaのリリースサイクルの変更に伴い、JJUG CCCの開催も半年に1回となりました。
日本の方々だけではなく、海外の著名な方々も多数参加されているということもあり、日本のJavaのイベントでは最大級のものとなっております。

 

会場の様子

iOS の画像 (3)

IMG_20191123_142305213

私にとって4度目の参加となるJJUG CCC。毎回セッションにテーマがあるように感じており、今回はサーバレス時代におけるJavaについて語られているセッションが多かった印象でした。以下が私が聴講してきたセッションのまとめとなります。

 

Coding That Sparks Joy with Quarkus (Edson Yanaga)

JavaチャンピオンであるEdson Yanagaさんの発表でした。Javaの有名なフレームワークというとSpring Frameworkが思いつく方が多いかもしれませんが、最近は様々な他の選択肢が出てきました。今回はその内の1つであるQuarkusについての話でした。
今までJavaは起動速度やメモリ使用量に対してそこまで意識しなくてもよい世界にいました。しかしながら、サーバレス時代になってきた今、そうもいかなくなってきました。
オートスケーリングさせるために出来るだけ起動速度を早くしなければならなく、現状Spring Bootなどの全部入りのフレームワークでは厳しいところもあります。
そういった時代にJavaもついていくためにもQuarkusのようなフレームワークが誕生しました。
Quarkusはアプリケーションの起動速度を削減しただけではなく、メモリ使用量の削減、また小さなサイズのコンテナイメージを作成することができます。
Edsonさんの発表ではQuarkusの凄さをライブコーディングで伝えてました。
私自身Quarkusに関する知識不足でQuarkusの凄さの全容を知ることができませんでしたが、とても使ってみたいという気持ちになりました!

 

Javaで学ぶオブジェクト指向プログラミングの基礎知識 (増田 亨)

「現場で役立つシステム設計の原則」の著者である増田亨さんによる発表でした。聴講の対象者としては、オブジェクト指向プログラミング初心者とのことでしたが、
増田さんの発表は毎回得るものが多く、改めてオブジェクト指向プログラミングというものを考えてみようということで聴講させていただきました。
今回のキーワードは「型」、「カプセル化」でした。それぞれのキーワードについてとても丁寧に説明されており、
自身が普段心がけていたことが間違っていなかったと再確認することができました。
オブジェクト指向プログラミングには2つのモード(モード1とモード2)があります。モード1はJava標準の型だけ使い、モード2は独自の型を自身で定義するものとのことです。
増田さんは本当のオブジェクト指向プログラミングの旨味はモード2にあり、型の消費者ではなく型の生産者になることが重要とおっしゃってました。
この言葉を忘れず日々努力していきたいと感じました。

 

開け!ドメイン駆動設計の扉(成瀬 允宣)

GMOインターネットの成瀬允宣さんの発表でした。私自身、今年の春のCCCの時に成瀬さんのドメイン駆動設計のお話を聴かせていただいてとてもわかりやすかったため、今回はドメイン駆動設計を周りの人に知ってもらうためにこちらの発表を聴かせていただきました。
今回の内容は、ドメイン駆動設計に興味はあるけど、Eric Evans氏の書籍に手を出すのは、、、という方向けの発表でした。
私自身も同じような感じで興味があったけど、なかなかあの厚さの書籍に手を出せなかった時期もあったので、こういった発表は初学者にとっては後押しとなり嬉しいと感じました。
最近になってドメイン駆動設計が流行りだした理由としては、10年ほど前にドメイン駆動設計にトライしたプロジェクトが今になって変更に耐えうるものになってきて、それが注目されだしたかららしいです。
話の内容としてはこの前に聞いた増田さんの「Javaで学ぶオブジェクト指向プログラミングの基礎知識」と結構かぶるところもあり、オブジェクト指向プログラングをしっかりしていれば対応できるようなところもあるように感じました。
ドメイン駆動設計において一番大事なことはドメインエキスパートとの会話がとても大切で、当たり前のことを当たり前にやることであるらしいです。確かに当たり前のことを当たり前にやること自体が1番難しいことなのだとこの発表を聴いて知らされました。

 

長く続くサービスがモダンであり続けるためには(角田 拓己)

こちらは私が発表させていただいたものになります。初めての発表でありながら200名近くの方々に聴いていただきとても楽しかったです。
発表内容としては、長く続くサービスのモダンさを維持するためのメソッドを紹介していきました。
普段私が感じていることなど色々こちらのスライドに込めていますので、皆さんも何か感じるところがあればうれしいかぎりです!!

 

Javaの起動速度といかに戦うか(きしだ なおき)

 LINE Fukuokaのきしださんによる発表でした。最初の方にも少し述べていますが、Javaの起動速度をいかにして短縮させるかについての話でした。
新規で作成するようなアプリケーションや、マイクロサービスのような単機能のものでよければQuarkusやMicronautのようなフレームワークを利用することで解決できるかもしれませんが、
既存のアプリケーションに対して起動速度をあげようとした場合、このようなフレームワークの置き換えは気軽にできるものではないと思います。そのような場合、今回はなされた内容が適用できるかもしれません。
スライドにも記載されてますが、そもそもJDKを8から13に単純に置き換えるだけでも約100msほど早くなっているようです。これはJava12からDefault CDS(Class Data Sharing)でCDSが効いていることが要因らしいです。また他に起動速度を早くする手段として今回のCCCで私が聴いたセッションの半分以上で出てきたGraalVMによるNative Imageの作成です。Native Imageにすることで起動速度は大幅に短縮できるそうですが、スループットは逆に悪くなるそうなので、この辺はどのような環境で使うかによって考えた方が良さそうです。
きしださんの発表は過去のCCCや勉強会で聴かせていただいたこともあり、今回も僕のような初心者でもわかりやすく解説してくださってました。

Serverless時代のJavaについて(下川 賢介)

Amazon Web Servicesの下川さんによる発表でした。こちらもサーバレス環境におけるJavaの最適化についての話で、特にAWS Lambdaに着目したお話でした。
今までと同じようにAWS LambdaでもSpring Bootのjarを載せようとするとコールドスタート問題が発生してしまうとのこと。出来るだけフレームワークを利用せず、
プレーンJavaでLambdaの関数を定義するのがベストらしいです。とはいえ、フレームワークの恩恵を受けて実装したいときは、最初から全部入りのフレームワークを利用するのではなく、
最小構成に単機能のライブラリを追加していくことで多少コールドスタート問題は解決するらしいです。とはいえやはりSpring Bootに慣れてるためSpring Bootを使いたいという時に
aws-serverless-java-containerというものが用意されているそうです。このようにサーバレス時代になり、今まで考えてこなかった部分(Javaの起動速度など)も考えていかないといけなくなったため、このようなベストプラクティス的な発表はとてもありがたかったです。

 

JVMs in Containers: Best Practices(David Delabassee)

OracleのDavid Delabasseeさんによる発表でした。こちらはコンテナ環境におけるJVMのベストプラクティスのお話でした。
様々な視点からベストプラクティスを話されていました。
例えば、コンテナイメージのサイズを下げるためにJDKをそのまま利用するのではなく、JDK9から入っているjlinkを使ってカスタムランタイムイメージを作成することでサイズを小さくできるそうです。アプリケーションの起動速度に関しては他の方の発表でもありましたが、JDK13を利用するだけでdefaultでCDS(Class Data Sharing)が利用されているため、JDK8に比べて早くなります。このようにコンテナの最適化するにはDockerイメージを出来るだけ小さくすることと、アプリケーション自体の起動速度を早くすることが求められるとのこと。
またDavidさん曰くJDK8はコンテナに最適化されていないため、新しいものを使うことをオススメするとのことでした。
私自身コンテナ周りの知識があまりなかったですが、これから勉強しようとしていたのでとても勉強になりました。

 

懇親会の様子

iOS の画像 (4)

CCCの懇親会といえば毎回恒例となっているLINE寿司です!!
とても美味しかったです!!いつもありがとうございます!!!
今回は登壇したこともあり、ありがたいことにたくさんの方々とお話しさせていただきました。

 

まとめ

最初にも述べていますが、今回はサーバレス時代におけるJavaについて語られていたセッションがとても多いイメージでした。
そのほかにもたくさん面白いセッションがありましたので、こちらからご覧になってみてください!!


2017年03月17日

araki

DroidKaigi 2017 に参加しました。会場の様子をレポートします!

コンテンツ・メディア第1事業部の荒木です。ピクトリンクというプリントシール画像を使ったアプリの Android 版を開発しています。

前回の記事では、DroidKaigi 2017 の参加前レポートを書きました。今回は、DroidKaigi 2017 の参加後レポートとなります。ほとんどのセッションはスライドと動画が公開されるようなので、この記事では DroidKaigi に参加できなかった方に向けて、会場の様子をお伝えします!

DroidKaigi とは?

※ 前回の記事と同じ内容を、再掲いたします。

公式サイト より引用:

DroidKaigiはエンジニアが主役のAndroidカンファレンスです。
Android技術情報の共有とコミュニケーションを目的に、2017/3/9(木)、3/10(金)の2日間開催します。

DroidKaigi とは、Android エンジニアのカンファレンスです。参加者は500人を超え、日本国内の Android カンファレンスとしては最大級の規模を誇ります。2015 年から開催されており、今回の DroidKaigi 2017 で3回目の開催となります。私は今回が初めての参加となります。

会場の様子

会場の様子をレポートいたします。今回の会場は、ベルサール新宿グランド コンファレンスセンターでした。

セッション

セッションルームは全部で6つありました。どのセッションも多くのエンジニアが発表を聞きに来ており、人気のセッションでは立ち見の人が出るほどでした。写真は Room3 の真ん中くらいから撮影したもので、私の後ろにもたくさんの聴講者がいました。

Session Room3

Session Room3 の様子

ランチ、おやつ

会場には、お菓子部屋がありました。各社のロゴの入ったお菓子や、マフィンなどがおいてあります。運営の方曰く、無限に湧いてくるとのことでした。

IMG_20170310_095808

 

他にも記念撮影スポットがあったり、

IMG_20170309_184112

 

バリスタの方がコーヒーを淹れてくれるというサービスもありました。常に長蛇の列ができていて、私は飲みそびれてしまいました。。

オフィスアワー

各セッションの後には、オフィスアワーが設けられました。オフィスアワーでは、発表者の方が質問やフィードバックを受けるために、お菓子部屋にしばらく滞在していました。発表者の周りには多くのエンジニアが集まり、発表内容について熱い議論を交わしていました。私もオフィスアワーで議論に参加したり、発表内容に関する疑問をぶつけてみたりしました。こうした貴重な経験は、カンファレンスに参加したからこそ得られるものだと感じました。

 

こちらのセッションのオフィスアワーで、MVVM について発表者の方と議論を交わしていました。とても楽しかったです!

アフターパーティー

全てのセッションが終わった後のアフターパーティーの様子です。ここでも、たくさんのエンジニアの方たちと交流することができました。

IMG_20170310_183106

 

寿司職人が握るお寿司。去年もあったそうです。大人気で、すぐに売り切れてしまいました。

IMG_20170310_191355

 

遠いですが、運営責任者の mhidaka さんが壇上にいらっしゃいます。この後、運営スタッフの方々に会場全体から感謝の拍手がありました。スタッフの方々のおかげでカンファレンス中、気持ちよく過ごすことができました。ありがとうございました!

IMG_20170310_202008

さいごに

今回は、DroidKaigi に参加できなかった方に向けて会場の様子をお伝えしました。楽しそうな雰囲気が伝わって「来年は DroidKaigi に参加するぞ!」と思っていただければ幸いです。私は来年も参加する予定ですので、ぜひみなさんも参加しましょう!


2016年10月13日

sakata

JavaOne 2016 サンフランシスコに参加しました!(その4) #javaone #j1jp

Hello world! コンテンツ・メディア第1事業部のjyukutyoこと阪田です。

前回はコレクションのセッションについてのレポートでした。今回はクラスローダーのセッションについてレポートします。

Join the War on ClassLoader Leaks

スライドはこちらにあります。

https://static.rainfocus.com/oracle/oow16/sess/1461358415846001E0TZ/ppt/Classloader%20leaks%20public.pptx

内容

java.lang.OutOfMemoryError(OOME)はみな出会ったことがあるだろう。Java 8になってPermGen spaceとは出なくなったが、代わりにMetaspaceが出るようになった。ローカルでの開発時にも、継続的デプロイでもOOMEは出る。このセッションのアジェンダは次のようなものだ。

  • OOMEは何を意味するのか?
  • OOMEはなぜ起こるのか?
  • どこでリークするのか?
  • どのように避けるのか?
  • OSSの例
  • トレーニング

OOMEは何を意味するのか?

JVMのメモリはヒープとPermGen/Metaspaceとスタックである。スタックはスレッドごと、ローカル変数やメソッドのパラメータを持つ。ヒープはオブジェクトのインスタンスを持つ。PermGen/Metaspaceはjava.lang.Classインスタンスなどを持つ。PermGenという名前はJava EEとクラスのアンロードができる前に名付けられた。Java 8でMetaspaceへ置き換えられた。OOME PermGen space/Metaspaceは、あまりに多くのクラスをロードしたときに起こる。

OOMEはなぜ起こるのか?

OOME PermGen space/Metaspaceが起こる原因は次の2つが考えられる。

  1. アプリケーションが大きすぎる。Java 7までは-XX:MaxPermSize=256Mなどと指定すればよい。Java 8ではMetaspaceは自動的に増えていく。
  2. java.lang.Classインスタンスが再デプロイ後にガベージコレクトされない

参照の型は次の4つがある。

  • 強い参照:到達可能なときは決してGCされない
  • ソフト参照:OOMEになる前にGCされる
  • 弱い参照(WeakHashMap):強い参照とソフト参照がないときにGCされる
  • ファントム参照:GCは妨げない

GCの到達可能性は以下の図のようなことである。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-10-05-17-40-30

再デプロイでは、新しいWARファイルをデプロイすれば前のクラスローダはGCされる。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-10-05-17-43-30

クラスローダーの参照は次の図のようになる。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-10-05-17-44-55

どのようにリークが起きるのか。GCルートからクラスローダへ到達可能だと、クラスローダをGCすることができない。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-10-05-17-45-38

どこでリークするのか?

Tomcatなどアプリケーションサーバのバグだ。他にCommons LoggingやLog4Jなどロギングフレームワークのバグ、Bean Validation APIやUnified Expression Languageのバグといったこともある。

GCルートでも起こる。まず、システムクラスローダによってロードされるクラス。JDKのクラスにおけるstaticフィールドで起こる。ライブスレッドではローカル変数、メソッドのパラメータのスタック、java.lang.Threadインスタンスで起こる。

システムクラスでは、java.sql.DriverManagerやBean introspectionのキャッシュ、シャットダウンフック、カスタムでデフォルトにしたAuthenticator、カスタムのセキュリティでのProvider、カスタムMBean、カスタムのThreadGroup、カスタムのプロパティエディタ…最初の呼び出し元でのcontextClassLoaderへの参照などで起こる。

DriverManagerをもう少し詳しく見てみよう。たとえばMySQLのJDBCドライバを使うときはこうするだろう。

com.mysql.jdbc.Driverクラスにはstaticイニシャライザがある。

registerDriver()メソッドは以下のようになっている。

このregisterDriversという変数は、以下のものだ。

図で表すと以下のようになる。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-10-06-16-55-03

そのため、コンテキストのシャットダウンで以下のように書かなければ、リークしてしまう。

スレッドもここで止めておかなければならない。次のようにスレッドを実装するのは悪いアイデアだ。

止められるようには以下のようにする。

このことは、次の記事に紹介されている。

Heinz Kabutz / Java Specialists’ – The Law of the Blind Spot

次にThreadLocalについて考えてみよう。次のように実装してはならない。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-10-06-17-09-13

ThreadLocalのJavaDocには以下のようにある。

Each thread holds an implicit reference to its copy of a thread-local variable as long as the thread is alive and the ThreadLocal instance is accessible; …

各スレッドは、スレッドが生存していてThreadLocalインスタンスがアクセス可能である間は、スレッド・ローカル変数のコピーへの暗黙的な参照を保持します。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-10-06-17-13-40

プールされたスレッドではスレッドはクラスローダより長生きする。ThreadLocalはThreadGlobalになる!

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-10-06-17-17-35

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-10-06-17-18-20

ThreadLocalMapのJavaDocには以下のようにある。

However, since reference queues are not used, stale entries are guaranteed to be removed only when the table starts running out of space

(私訳)しかしながらリファレンスキューが使われないので、テーブルが容量不足になり始めたときだけ失効したエントリが削除されることが保証されます。

参照を含んだカスタムの値は、staticなThreadLocalであればリークし、そうでなければ予測されていないGCとなる。カスタムのThreadLocalであればリークしない。

ThreadLocalはクリアするようにしよう。

実際には、多くのOSSライブラリが違反している。

どのように避けるのか?

リーク防止のライブラリがある。アプリケーションサーバ非依存、Tomcatよりも多くをカバーしており、ログで警告を出力、ライセンスはApache 2ライセンスだ。実行時の依存は0で、設定は必要ない。Mavenであれば以下のように依存ライブラリを追加する。

これはServlet 3.0以降用だが、2系のものもある。

OSSの例

Bean Validationの1.0.0.GAでは以下のようになっていた。

(私訳)List<ValidationProvider>はキーであるクラスローダに強い参照を持っている。JPAのCachingPersistenceProviderResolverと同じモデルを使うようにして。

jyukutyo調査

Bean Validationの1.1.0.GAではこのクラスは次のようになっています。

providersPerClassloader.put( classLoader, new SoftReference<List<ValidationProvider<?>>>( providers ) );とあるので、ソフト参照を使うようになったようです。

JPAのCachingPersistenceProviderResolverクラスも調べてみました。

その他のOSS

javax.el.BeanELResolverやorg.apache.cxf.transport.http.CXFAuthenticator、com.sun.star.lib.util.AsynchronousFinalizerも該当する。

トレーニング

Eclipse Memory Analyzer(MAT)を使おう。

http://www.eclipse.org/mat/

次のオプションをつけてアプリケーションを実行しよう。

感想

最後に出てきた、MATについてはこのブログで私が記事を書いています。

ヒープダンプをEclipse Memory Analyzerで解析しよう!

セッションとしては非常におもしろかったです。とくにOSSの実例を挙げながらリークの原因を解説する箇所ではとても興奮しました。こういう内容のセッションはJavaOneだと他にもいろいろとあります。なかなか普段の勉強会でこの分野を扱っていることは少ないと思いますので、興味がある人にはJavaOneはとても楽しめるカンファレンスです!


2016年10月12日

sakata

JavaOne 2016 サンフランシスコに参加しました!(その3) #javaone #j1jp

Hello world! コンテンツ・メディア第1事業部のjyukutyoこと阪田です。

前回はAngular 2とGWTのチュートリアルセッションをレポートしました。今日はJDKの開発者であるStuart Marksさんのセッション”Collections Refueled”をレポートします。

Collections Refueled

スライドはこちらにあります。
https://stuartmarks.files.wordpress.com/2016/09/collectionsrefueled-final.pdf
タイトルの通り、Javaのコレクションフレームワークについての話です。その歴史とJava 8での拡張、Java 9での拡張と将来の作業についてでした。

内容

JDK 1.0はレガシーコレクション、VectorやHashtableなどである。1.2はコレクションフレームワークが導入された。インタフェースとしてCollection、List、Set、Map、Iteratorが、具象クラスとしてArrayList、HashSet、HashMap、TreeSet、TreeMapがある。5.0ではジェネリクス、java.util.concurrentパッケージが追加された。

Java 8

Java 8ではラムダとストリームが追加され、インタフェースにデフォルトメソッドとstaticメソッドが定義できるようになった。15年経って初めての変更だ。

 


CollectionはIterableのサブインタフェースなので、これはすべてのコレクションで動作する。
Iteratorインタフェースでは、ほとんどのイテレータは削除をサポートしていない。そのためこう書く必要があった。



remove()のデフォルトメソッドがまさにこれだ。削除できないイテレータを作るときは、単にremove()を省くだけでよい。削除できるものを書くときは、remove()メソッドをオーバーライドするだけだ。

Collectionインタフェースでは、removeIfでバルク更新ができるようになった。


もしコレクションがArrayListなら、7の場合の計算量はO(n^2)であり、8の場合はO(n)となる。

List

ListインタフェースのreplaceAllもバルク処理だ。


ただし、要素の型を変更することはできない。そうしたいときはStreamを使う。

List.sortはCollections.sortよりなぜよいのか?Collections.sortは3つのステップを使う。

  • 一時的な配列にコピーする
  • 配列をソートする
  • リストにコピーして戻す

List.sortはデフォルトでは上記と同じだが、ArrayList.sortはオーバーライドしてin-placeでソートするため、コピーはしない。Collections.sortは現在単にList.sortを呼び出すだけだ。

Map

MapインタフェースにもforEachがある。



replaceAllもある。



Java 7までMulti-mapはとても扱いづらかった。Multi-mapはキーに対して複数の値があるマップだ。

Java 8ではこうなる。

Comparator

Comparatorを書いて楽しい人はいる?Comparatorは多くの条件とコードの繰り返しだ。Java 8はComparatorにstaticとデフォルトメソッドを追加した。名字とnullがある名前でソートし、nullを最初に持ってくる2レベルのソートのサンプルを見てみよう。まずはJava 7から。

Java 8ではこうできる。

Java 9

JEP 269: Convenience Factory Methods for Collectionsだ。こういったAPIが追加される。

設計と実装の課題としては以下のものがあった。

  •  Immutability
  •  Iteration Order
  •  Nulls Disallowed
  •  Duplicate Handling
  •  Space Efficiency
  •  Serializability

新しいstaticファクトリメソッドが返すコレクションはイミュータブルとなる。これは従来の不変性であり、不変の永続性ではない(addなどはUnsupportedOperationExceptionをスローする)。不変性はよいものである。一般的な場合、コレクションは既知の値で初期化した後、変更することはない。不変であれば自動的にスレッドセーフになる。効率、とくにスペースについて改善するチャンスがある。JDKには一般的な目的のための不変コレクションはない。

Setの要素とMapのキーのイテレーションの順序については、HashSetやHashMapであれば公式には順序が保証されないとしていたが、長い間たいてい一貫していた。これを変更すると、順序に依存しているコードは動作が変わってしまう。適用するのは新しいコレクション実装だけにする。既存のコレクションは同じままとなるだろう。

ListやSetの要素、Mapのキーや値にnullを許可しない。NullPointerExceptionをスローする。1.2でコレクションにnullを許可したのは失敗だった。Java 5以降コレクションではnullを許可していない。とくにjava.util.concurrentのコレクションではそうだ。nullはNullPointerExceptionの原因だからだ。

Setの要素やMapのキーで重複したときはIllegalArgumentExceptionをスローする。”コレクションのリテラル”で重複があるのはプログラミングのエラーである可能性が高い。理想的にはこれをコンパイル時に検出する。値はコンパイル時の定数ではない。次にいいのは、実行時の生成においてフェイルファストにする。

2つの文字列の要素を持つSetを考えてみる。

どのぐらいスペースを使っているのか?オブジェクトを数えてみる。

  • unmodifiableなラッパーが1つ
  • HashSetが1つ
  • HashMapが1つ
  • 長さが3のObject配列のテーブルが1つ
  • Nodeオブジェクトが2つ、各要素に1つずつ

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-10-03-14-36-08

サイズの見積もりとしては、オブジェクトごとに12バイトのヘッダーがある(64ビットJVMで32GB未満のヒープ、OOP圧縮あり)。int、float、参照フィールドごとにプラス4バイトだ。ということは、先ほどのオブジェクトを合計すると152バイトになる。

 

  • unmodifiableなラッパー: ヘッダー + 1フィールド = 16バイト
  • HashSetが1つ : ヘッダー + 1フィールド = 16バイト
  • HashMapが1つ: ヘッダー + 6フィールド = 36バイト
  • 長さが3のObject配列のテーブル: ヘッダー + 4フィールド = 28バイト
  • Nodeオブジェクトが2つ、各要素に1つずつ: (ヘッダー + 4フィールド) * 2 = 56バイト

フィールドベースのSet実装だとオブジェクト1つとフィールド2つで20バイトとなる。

 

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-10-03-14-43-09

実装はすべてstaticファクトリの背後にあるプライベートなクラスとしている。

コレクションはすべてシリアライズできる。ただ、デフォルトのシリアライズ形式は内部実装について漏らしてしまっていた。新しいコレクションの実装は、カスタマイズしたシリアライズ形式となる。

将来的な作業

これらはまだ計画されていない将来的な作業だ。

VectorやHashtableといったレガシーなコレクションは非推奨にする。LinkedListもそうするかもしれない。

コアなコレクションのイテレーション順序をランダムにする。新しいミューテータのデフォルトメソッドを追加する。ArrayDequeへのインデックスアクセスを追加する。

JEP 269のコレクション拡張では、パフォーマンスの改善と、順序があるSet/Mapを追加する。

Project ValhallaでのValue typesなど。

感想

Stuartさんのセッションは熱い感じで印象深かったです。これはStuartさんの最後のセッションでしたが、他2つ、Stuartさんのすべてのセッションを聴きました。

このセッションの内容としては、Javaプログラミングで使わないことはほぼないであろう、コレクションについて歴史をたどれ、興味深いものでした。

JEP 269については、以前私は個人ブログにて動作確認していました。

そのためAPIの追加は知っていました。しかしほかにも数多くの改善があり、とくにコレクションが使うスペースについて理解が深まったのはうれしいです。


2016年09月30日

sakata

JavaOne 2016 サンフランシスコに参加しました!(その2) #javaone #j1jp

Hello world! コンテンツ・メディア第1事業部のjyukutyoこと阪田です。

前回の投稿ではJavaOneへの行き方を中心に書きました。今後数回に渡っていくつかのセッションの内容を紹介します。

Building Angular 2 Applications in Java 8

チュートリアルセッションです。Angular 2とGWT、Spring Bootでアプリケーションを作るには、という内容でした。スライドはこちらにあります。
http://lteconsulting.fr/angular2boot-javaone/#/
Angular 2とGWT 2.8を使う際の問題点と解決策が中心となっています。

内容

Angular 2はJavaScriptに加えてTypeScriptをサポートしている。Modules、Components、Dependency Injection、Change Detectionが基本的なものである。さらにJSR-269のPluggable Annotation Processing APIを使ってコードを生成する。バックエンドは、シンプルで強力なSpring Bootを使う。

GWTは今のWebからは遠いところにあるものなのは事実だ。GWTにあるものは、以下のもので置き換えられる。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-09-29-12-59-15

ただ、GWT 2.8は将来の過渡期にある。

  • JsInterop
  • Java 8対応
  • Widgetや古いものをなくす

GWT 3はJ2CL (Java to Closure) となり、今標準となっている多くの機能をなくす。

GWTはモダンで最適化されたJavaScriptへコンパイルしてくれる。JsInteropはJavaScritpとJavaコード間を双方向で統合する。JavaScriptのXMLHttpRequestは以下のようなJavaクラスとなる。
%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-09-29-13-16-14
これを次のように使うことができる。
%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-09-29-13-16-27
そしてSuper Dev Modeには開発用の早いインクリメンタルなコンパイラがある。

JSR-269のPluggable Annotation Processing APIでは、独自のアノテーションプロセッサを登録する。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-09-29-13-23-34

そして、Angular2GwtというGWTとAngular 2を統合するライブラリを使う。 Angular2Gwtがすべてやってくれる。User moduleなしのGWTのコンパイルは早い。アプリケーションに依存ライブラリを1つ足すだけでできる。

アーキテクチャは次のようになる。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-09-29-13-28-11

デモアプリケーション

セッションではデモもありました。デモのリポジトリはこちらです。
https://github.com/ltearno/angular2boot-demos

デモアプリケーションはいくつかあります。ここではセッションで実行していた”my-first-tree-orchard”を動かしてみましょう。

$ cd my-first-tree-orchard
$ mvn spring-boot:run

僕の環境ではjava.lang.IllegalArgumentException: Can not copy a non-root Methodが出ましたが、起動しました。http://localhost:8080/にアクセスすると、”Application is loading”が出た後、次の画面になります。

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-09-29-13-53-23

あとは”Roll 6 faces dice”ボタンを押せば動作します。

さて、target/generated-sourcesディレクトリを見ると、コードが生成されています。
%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-09-29-14-00-06
ライブラリがPluggable Annotation Processing APIを使って生成したコードですね。

このままではコンポーネントのテンプレートを変更しても、即座に反映されません。Super Dev Modeを使ってみましょう。spring-boot:runはしたままで、別のウィンドウを使って同じディレクトリで次のコマンドを実行します。

$ mvn gwt:run-codeserver
...
[INFO] Super Dev Mode starting up
...

Super Dev Modeが起動しました。画面をリロードします。”Compileing Application”と表示されるようになります。

最後に、起動時のjava.lang.IllegalArgumentException: Can not copy a non-root Methodですが、古いバージョンのSpring Loadedの問題のようです。angular2boot-demosディレクトリにある親pom.xmlのspringloadedを1.2.0から現時点で最新の1.2.6にすると、例外は出力されなくなりました。

感想

Angular 2にもGWTにもほとんど知識はありませんでしたが、おもしろいアプローチではあると感じました。現時点ですぐにJavaにすべてを寄せるアプローチを使う予定はないのですが、こういった方法もあることは知っておいてよいですね。