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

プロジェクト導入後のメリット・デメリットは下記をご覧ください。
[EclipseCollectionsをプロダクトで導入した結果、メリット・デメリット](http://qiita.com/kohei789/items/cce99db97cd72fd3a230)

---
# 1, EclipseCollectionsとは

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


# 2, EclipseCollectionsを使う理由

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

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


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

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

```title:ユーザオブジェクトの中でスコア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;
```

```title:ユーザオブジェクトの中でスコア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);
```

```title:結果
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));
```


```title:結果
[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);
```

```title:結果
[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と同様
```
```title:結果
[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());
```

```title:結果
[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));
```

```title:結果
[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()));

```
```title:結果
{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()));

```

```title:結果
{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"))
);
```

```title:結果
{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());
```

```title:結果
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()));

```

```title:結果
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()));
```

```title:結果
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);
```

```title:結果
[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を返却します。
１つでも一致しない物があればfalseとなります。

```
ImmutableList<Integer> numList = Lists.immutable.of(1, 2, 3, 4, 5, 6);
System.out.println(numList.allSatisfy(num -> num >= 3));

```

```title:結果
false
```
### 4.16 anySatisfy

　対象リストに対して、条件が**１つでも満たされる場合**trueとなります。

```
ImmutableList<Integer> numList = Lists.immutable.of(1, 2, 3, 4, 5, 6);
System.out.println(numList.anySatisfy(num -> num >=6));
```

```title:結果
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));
```

```title:結果
true
```
### 4.18 maxBy
　指定したリストに対して指定した条件での最大値を取得する。

```
ImmutableList<String> strList = Lists.immutable.of("tom", "john", "david");
System.out.println(strList.maxBy(str -> str.length()));
```

```title:結果
david
```


### 4.19 minBy
 maxByの逆です。

```
ImmutableList<String> strList = Lists.immutable.of("tom", "john", "david");
System.out.println(strList.minBy(str -> str.length()));

```

```title:結果
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なども存在しそちらも便利な関数が存在します。また機会があれば紹介できればと思います。