GS Collections 道場[ハンズオン]に参加してきました!
小酒です。
昨日、GS Collections 道場[ハンズオン]に参加してきました!
久しぶりの勉強会のような気がします^^
今年4月に開催された Java Day Tokyo 2015で発表を聞いてその存在は知っていたのですが、実際に触れたのは今回が初めてでした。
GS Collectionsはゴールドマン・サックスが開発し、2012年にGitHubに公開したオープンソースJavaコレクションフレームワークです。Apache License Version 2.0で提供されており、Java 7以前でも使用できます*1!JavaのStream APIよりもより簡潔に書けることや、mutableやimmutableなコレクションインタフェースが用意されているのが好ましいと感じています。
GS Collections の説明や資料についてはconnpassのイベントページに詳しく纏まっております。興味のあるかたは、以下URLの下部にあるリンクを参照してください。
GS Collections 道場[ハンズオン][OSS コレクションフレームワーク] - connpass
ハンズオンでは、「GS Collections Kata」というゴールドマン・サックスの社内研修でも使われているトレーニングキットを用いて行いました。
Fail状態のJUnitテストを研修の中でひとつひとつパスしていきます。
仕事現場において、プロジェクトに途中参加するメンバへの各種教育はいつも悩みの種ですが、このようにゲーム感覚で楽しく学べるトレーニングキットが用意されているのは素晴らしいと感じました。
今回のハンズオンでは、インストラクターの方が壇上でライブコードしながらそのコードの説明をし、参加者がそれを写経する流れとなりました。時間の関係からの短縮手法でしたが、それでもかなりの勉強効果があるように感じました。実際に手を動かすとやはり理解の進みが違いますね!
GS Collections の楽しさや魅了を感じるには、資料を読んで実際のKata をやってみることをお勧めします。そのハンズオンの中で、僕が一番興味の湧いたコードを一つ紹介してみたいと思います。
次のコードは、いくつかの商品を保持するサプライヤーが存在する状況で、商品名をキーにその商品を保持するサプライヤーの一覧を保持するMapを作成します。
仕様が分からない状況で、上のコードを読むのは少々骨が折れると思います。これをGS Collectionsを用いると、次のコードとなります。
mapOfItemsToSuppliersByGSCollections
groupByEachメソッドを用いることで、シンプルに書けます。一度このメソッドがどのような操作を提供するかを知れば、次からは同じようなロジックを簡潔に表現できるようになります!このようにアルゴリズムの再利用がより促進されるのが、Java8 ラムダがJavaにもたらした福音だと個人的に考えています。
なお、上のコードをStream APIで書いてみると次のとおりとなります。
Tupleは自作しました。SupplierのStreamをflatMapで商品名をFirstとするTuple<String, Supplier>のStreamに変換して、collectでgroupingBy。その中でTuple<String, Supplier>のリストをSupplierのリストに変換する。。
う〜ん、ややこしい^^;
これならStream APIを使わずに書いた方が可読性がいいと判断してしまうかもしれません。
この一例からも分かるように、GS CollectionsにはStream APIにはない様々な機能が備わっております。今後Javaのバージョンが上がるにつれ、このような機能がStream APIにも備わってくるでしょう。
いち早くStream APIの未来に触れたみたいで、とても充実した一日でした!
インストラクターの伊藤さんとチューターの佐野さんをはじめ、関係各位のみなさん、本当ありがとうございました(((o(*゚▽゚*)o)))!!
その後は懇親会でビールを飲んで、二次会でもガンガン飲んで、めちゃくちゃ楽しかったです!!今日は昼間までくたばってましたがww
(追記)
このブログを公開した後、@backpaper0 さんからコメント頂きました!
@s_kozake Stream APIを使う例、考えてみました https://t.co/Phex9pSMuG
— うらがみ (@backpaper0) 2015, 6月 14
Stream APIは便利なCollector生成メソッドを作るのがキモっぽい。
— うらがみ (@backpaper0) 2015, 6月 14
https://gist.github.com/backpaper0/59bf51b8c1d8804c3611
このように、独自でCollectorを実装すると、Stream APIでも簡潔に処理を記述できますね!
ただ、その後、@bitter_fox さんとのやりとり
@backpaper0 @s_kozake 細かい話ですがCollector.ofの3つ目引数よくないですね・・・多分,並列で実行した場合一部のデータが欠落しちゃう可能性があります.
— bitter_fox (@bitter_fox) 2015, 6月 14
@backpaper0 @s_kozake (基本的にはMap<K, List<V>>同士の結合は重たいので,並列向けには一つのj.u.cのMapに突っ込むという形がベストですが・・・)
— bitter_fox (@bitter_fox) 2015, 6月 14
Collectorクラスには独自のCollectorクラスを作成するofメソッドが用意されています。
- 第一引数に新たなインスタンスを作成するサプライヤー(ここではHashMapのコンストラクタ)
- 第二引数にオブジェクトに要素を追加するアキュムレータ
- 第三引数に2つのオブジェクトを1つのオブジェクトへとマージするコンバイナ
を指定します*2
ここでの例では、コンバイナにputAllを使っているので、同じキー同士の場合にリストの結合が必要な処理が抜けているというのが@bitter_fox さんの指摘だと思います。
本来であれば、Map<String, List>の結合は重いので、1つのConcurrentHashMapで全て出来ればいいのだけどって話も続いていますが、Collectorがそのような考えでは作られていないのかもです。せめて、リストの追加は処理の重いArrayListよりLinkedListを用いたほうがいいかもとか、そのようなことを考えました。
Collectorを生成する場合は、並列動作について問題なく動作する仕組みを考える必要があります。まあ、そのようなコードは総じて難度が高くてミスを犯しやすいので、やっぱり標準メソッドで用意してくれたらな〜^^; って考えちゃったり。
まあ、パラレルストリームなんて業務で使わry)
*2:更なる情報はJava SE8 実践プログラミングのp.42に詳しく書かれています。
Javaプログラマーなら習得しておきたい Java SE 8 実践プログラミング
- 作者: Cay S. Horstmann,柴田芳樹
- 出版社/メーカー: インプレス
- 発売日: 2014/09/22
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (8件) を見る