LoginSignup
3
1

More than 5 years have passed since last update.

EclipseCollections(旧GS Collections)の使い方 - java8

Last updated at Posted at 2016-11-01

プロジェクト導入後のメリット・デメリットは下記をご覧ください。
EclipseCollectionsをプロダクトで導入した結果、メリット・デメリット


1, EclipseCollectionsとは

 Java のコレクションフレームワークで、かつてGoldman SachsがGS Collectionsとして公開しており
それをEclipseに移管したものです。

2, EclipseCollectionsを使う理由

  1. メモリ効率が良いコンテナ
  2. 豊富かつリッチな関数
  3. 終端操作不要・再利用可能

 この辺は他でもよく語られているので割愛しますが、
「こういうことをやりたいなあ」と思って探すとほとんど存在するぐらい、非常に関数群の数が多いです。
またstreamの場合、stream生成・終端操作が必要になりコードがさほど短くならないため導入を見送った経緯がありますが、そういった問題も解決してくれました。

3, どのぐらい短くなる?Example編

 下記はシンプルな一例ですが、ユーザーオブジェクトの中から条件を満たす者を抽出する場合です。
これがもっと複雑な処理や、マップなどが絡むと更にコード量が顕著になります。
 また関数の中で渡される変数はイミュータブルであるため、変数の一つ一つのスコープが小さくなることもメリットの1つです。

ユーザオブジェクトの中でスコア50点未満を排除し、男性のみを抽出する。

        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;
ユーザオブジェクトの中でスコア50点未満を排除し、男性のみを抽出する。
        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なども存在しそちらも便利な関数が存在します。また機会があれば紹介できればと思います。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1