プロジェクト導入後のメリット・デメリットは下記をご覧ください。
EclipseCollectionsをプロダクトで導入した結果、メリット・デメリット
1, EclipseCollectionsとは
Java のコレクションフレームワークで、かつてGoldman SachsがGS Collectionsとして公開しており
それをEclipseに移管したものです。
2, EclipseCollectionsを使う理由
- メモリ効率が良いコンテナ
- 豊富かつリッチな関数
- 終端操作不要・再利用可能
この辺は他でもよく語られているので割愛しますが、
「こういうことをやりたいなあ」と思って探すとほとんど存在するぐらい、非常に関数群の数が多いです。
またstreamの場合、stream生成・終端操作が必要になりコードがさほど短くならないため導入を見送った経緯がありますが、そういった問題も解決してくれました。
3, どのぐらい短くなる?Example編
下記はシンプルな一例ですが、ユーザーオブジェクトの中から条件を満たす者を抽出する場合です。
これがもっと複雑な処理や、マップなどが絡むと更にコード量が顕著になります。
また関数の中で渡される変数はイミュータブルであるため、変数の一つ一つのスコープが小さくなることもメリットの1つです。
List<Integer> userIdList = Arrays.asList();
for (User user : userList) {
if(user.getScore() < 50){
continue;
}
if(Sex.MALE == user.getSex()){
userIdList.add(user.getId());
}
}
return idList;
userList.reject(user -> user.getScore < 50 )
.select(user -> Sex.MALE == user.getSex() )
.collect(adApp -> adApp.getId());
4, EclipseCollections使い方(ImmutableList編)
EclipseCollectionsの中でもよく使うコレクションクラスで、イミュータブルのため変更処理はできません。
変更処理をできるものとしてMutableListが存在します。
4.1 collect
リストに対して操作を加え返却します。
ImmutableList<User> list = Lists.immutable.of(new User(1, "john"), new User(2, "ken"), new User(3, "jim"));
ImmutableList<String> names = list.collect(u -> u.getName());
4.2 select
条件付き取得です。条件に一致するオブジェクトを取得しリストで返却します。
ImmutableList<User> list = Lists.immutable.of(new User(1, "john"), new User(2, "ken"), new User(3, "jim"));
list.collect(u -> u.getId().equals(2));//id=2のみ取得
4.3 detect
条件に一致した最初の要素を取得します。
存在しない場合nullが返却されるので、java8で使用する場合detectIfNoneを利用するか、Optionalでラップする必要があります。
ImmutableList<User> maleList = Lists.immutable.of(new User(1, "john"), new User(2, "ken"), new User(3, "jim"));
User user = maleList.detect(m -> m.getName().equals("john"));
System.out.println(user);
User(id=1, name=john)
4.4 take
リストから指定数を取得します。
ImmutableList<User> maleList = Lists.immutable.of(new User(1, "john"), new User(2, "ken"), new User(3, "jim"));
System.out.println(maleList.take(2));
[User(id=1, name=john), User(id=2, name=ken)]
4.5 drop
リストから指定数の要素を除いたものを返却します。
ただし元のリストに対して変更は行われておりません。
ImmutableList<User> maleList = Lists.immutable.of(new User(1, "john"), new User(2, "ken"), new User(3, "jim"));
System.out.println(maleList.drop(2));
System.out.println(maleList);
[User(id=3, name=jim)]
// 元のmaleListに変更は加わっていません。
[User(id=1, name=john), User(id=2, name=ken), User(id=3, name=jim)]
4.6 subList
添字の範囲を指定してリストから取得します。左引数は条件が以上で、右引数の条件は未満です。
ImmutableList<Integer> numList = Lists.immutable.of(1,2,3,4,5,6,7,8,9,10);
System.out.println(numList.subList(3,6));// 3<=i<6と同様
[4, 5, 6]
4.7 distinct
重複を排除してリストを取得します。
ImmutableList<Integer> numList = Lists.immutable.of(1,2,3,4,4,4,5,6,6);
System.out.println(numList.distinct());
[1, 2, 3, 4, 5, 6]
4.8 reject
リストから指定要素を排除して、リストで取得します。
ImmutableList<Integer> numList = Lists.immutable.of(1,2,3,4,5,6,7,8,9,10);
System.out.println(numList.reject(n -> n >= 4));
[1, 2, 3]
4.9 groupBy
指定したリストから条件を元にマップを生成します。注意点は返却されるのはImmutableMapではなくImmutableListMultimapとなっています。(keyに対してvalueが複数)
key生成条件がユニークな場合は結果も1:1となる。
ImmutableList<User> maleList = Lists.immutable.of(
new User(1, "john"), new User(2, "ken"), new User(3, "jim"), new User(4, "mike"));
System.out.println(maleList.groupBy(u -> u.getName()));
{jim=[User(id=3, name=jim)], ken=[User(id=2, name=ken)], john=[User(id=1, name=john)], mike=[User(id=4, name=mike)]}
key生成条件がユニークでない場合、結果は1:1ではない。
ImmutableList<User> maleList = Lists.immutable
.of(new User(1, "john"), new User(2, "ken"), new User(3, "jim"), new User(4, "jim"), new User(5, "john"));
System.out.println(maleList.groupBy(u -> u.getName()));
{jim=[User(id=3, name=jim), User(id=4, name=jim)], ken=[User(id=2, name=ken)], john=[User(id=1, name=john), User(id=5, name=john)]}
- 応用
取得したImmutableListMultimapに大して様々な操作ができます。
ここに一例を示します。
取得したMultimapに対して条件付きで取得する。
ImmutableList<User> maleList = Lists.immutable.of(
new User(1, "john"), new User(2, "ken"), new User(3, "jim"), new User(4, "mike"));
// 取得したkeyに対して条件に一致したものを取得する。第二引数はkeyのサイズが渡される。
System.out.println(
maleList
.groupBy(m -> m.getName())
.selectKeysMultiValues((name, size) -> name.equals("john"))
);
{john=[User(id=1, name=john), User(id=5, name=john)]}
4.10 partition
リストから指定した条件でパーティションを作成します。取得したPartitionImmutableListからはselectedとrejectedを取得できます。
ImmutableList<User> maleList = Lists.immutable.of(
new User(1, "john"),
new User(2, "ken"),
new User(3, "jim"),
new User(4, "jim"),
new User(5, "john")
);
PartitionImmutableList<User> userPtList= maleList.partition(m -> m.getId() >=4);
System.out.println("selected : " + userPtList.getSelected());
System.out.println("rejected : " + userPtList.getRejected());
selected : [User(id=4, name=jim), User(id=5, name=john)]
rejected : [User(id=1, name=john), User(id=2, name=ken), User(id=3, name=jim)]
4.11 each
指定リストに対してループ処理を実施します。戻り値はありません。
ImmutableList<User> maleList = Lists.immutable.of(
new User(1, "john"),
new User(2, "ken"),
new User(3, "jim"),
new User(4, "jim"),
new User(5, "john")
);
maleList.each( m -> System.out.println(m.getName()));
john
ken
jim
jim
john
4.12 tap
指定リストに対してループ処理を実施します。eachと異なり元のリスト型を返却するので、引き続き処理を実施できます。
ImmutableList<User> maleList = Lists.immutable.of(
new User(1, "john"),
new User(2, "ken"),
new User(3, "jim"),
new User(4, "jim"),
new User(5, "john")
);
maleList
.tap( m -> System.out.println(m.getName()))
.tap(m ->System.out.println(m.getName()));
john
ken
jim
jim
john
john
ken
jim
jim
john
4.13 zip
指定したリストに対して、同数のリストを渡すことで結合して1:1のPairを返却する。
ImmutableList<Integer> numList = Lists.immutable.of(1, 2, 3, 4);
ImmutableList<Pair<Integer, String>> pairs = numList.zip(Lists.immutable.of("one","two","three","four"));
System.out.println(pairs);
[1:one, 2:two, 3:three, 4:four]
4.14 asParallel
対象リストに対して並列実行を行う。asParallelの引数はExecutorServiceのため並列処理の種別や使用プロセッサ数も定義できる。
@Cleanup("shutdown") ExecutorService es = Executors.newFixedThreadPool(4);
list
.asParallel(es, limit) //リミットは実行処理のリミット件数
.forEach(summary -> {
// 実行処理
}
4.15 allSatisfy
対象リストに対して、条件が全て満たされる場合trueを返却します。
1つでも一致しない物があればfalseとなります。
ImmutableList<Integer> numList = Lists.immutable.of(1, 2, 3, 4, 5, 6);
System.out.println(numList.allSatisfy(num -> num >= 3));
false
4.16 anySatisfy
対象リストに対して、条件が1つでも満たされる場合trueとなります。
ImmutableList<Integer> numList = Lists.immutable.of(1, 2, 3, 4, 5, 6);
System.out.println(numList.anySatisfy(num -> num >=6));
true
4.17 noneSatisfy
対象リストに対して、全ての条件が満たされない場合にtrueとなります。
ImmutableList<Integer> numList = Lists.immutable.of(1, 2, 3, 4, 5, 6);
System.out.println(numList.noneSatisfy(num -> num >=10));
true
4.18 maxBy
指定したリストに対して指定した条件での最大値を取得する。
ImmutableList<String> strList = Lists.immutable.of("tom", "john", "david");
System.out.println(strList.maxBy(str -> str.length()));
david
4.19 minBy
maxByの逆です。
ImmutableList<String> strList = Lists.immutable.of("tom", "john", "david");
System.out.println(strList.minBy(str -> str.length()));
tom
5 おまけ
ImmutableList内のOptionalを排除する。
flatCollectを使用して内部のOptionalを排除する。
public static <T> ImmutableList<T> toImt(ImmutableList<Optional<T>> objOptList) {
return objOptList.flatCollect(objOpt ->
objOpt
.map(obj -> Lists.immutable.of(obj))
.orElse(Lists.immutable.empty())
);
}
6 終わりに
ズラッと羅列しましたが、実はまだまだほんの一部で今回は触れていませんがMap関連やBag, Tupleなども存在しそちらも便利な関数が存在します。また機会があれば紹介できればと思います。