最近、業務で半年ぶりくらいにJavaを書いている。
以前業務で使っていたのは**Java7(!)**だったのだが、現在Java8を使用している。
stream
を結構な頻度で使用しており、先日複数条件でソートできることを知ったため書き留め。
Java Stream API
反復処理や並行処理等、集約操作をサポートするAPI。
ラムダ式(JSでいうアロー関数)と組み合わせることで、拡張for構文等を使うことなくシンプルに記述できる。
複数条件によるソート
Comparatorインタフェースを使うことによって可能。
comparing()
やthenComparing()
メソッドによって、ソート条件を指定し、stream
のsorted()
に渡すことで、複数条件によるソートができる。
サンプルコード
設計の雑さについてはご容赦。
Article
クラス
import java.time.LocalDate;
public class Article {
/** 投稿者 */
private String contributor;
/** 投稿日 */
private LocalDate date;
/** いいね数 */
private int goodCount;
/** コンストラクタ */
public Article(String contributor, LocalDate date, int goodCount) {
this.contributor = contributor;
this.date = date;
this.goodCount = goodCount;
}
/** Getter, Setter */
public String getContributor() {
return this.contributor;
}
public void setContributor(String contributor) {
this.contributor = contributor;
}
public LocalDate getDate() {
return this.date;
}
public void setDate(LocalDate date) {
this.date = date;
}
public int getGoodCount() {
return this.goodCount;
}
public void setGoodCount(int goodCount) {
this.goodCount = goodCount;
}
}
Stream
クラス
import java.time.LocalDate;
import java.util.Arrays;
import java.util.List;
public class Stream {
public static void main(String[] args) {
// データ生成
Article a1 = new Article("Taro", LocalDate.of(2018, 7, 11), 15);
Article a2 = new Article("Taro", LocalDate.of(2015, 11, 1), 53);
Article a3 = new Article("Taro", LocalDate.of(2015, 10, 31), 54);
Article a4 = new Article("Hanako", LocalDate.of(2017, 2, 5), 53);
Article a5 = new Article("Hanako", LocalDate.of(2016, 11, 1), 160);
Article a6 = new Article("Hanako", LocalDate.of(2012, 8, 20), 22);
Article a7 = new Article("Pochi", LocalDate.of(2013, 3, 16), 38);
Article a8 = new Article("Pochi", LocalDate.of(2011, 9, 25), 200);
Article a9 = new Article("Pochi", LocalDate.of(2018, 4, 13), 10);
// リスト作成
List<Article> list = Arrays.asList(a1, a2, a3, a4, a5, a6, a7, a8, a9);
list.stream().forEach(a ->
System.out.println(a.getContributor() + " " + a.getDate() + " " + a.getGoodCount()));
}
}
とりあえず、a1
からa9
をリストにして出力すると
Taro 2018-07-11 15
Taro 2015-11-01 53
Taro 2015-10-31 54
Hanako 2017-02-05 53
Hanako 2016-11-01 160
Hanako 2012-08-20 22
Pochi 2013-03-16 38
Pochi 2011-09-25 200
Pochi 2018-04-13 10
となる。
ソート処理
Comparator
を引数に渡し、指定した順序でソートする。
単項目でのソート
辞書的に名前順でソート。
// Comparator作成
Comparator<Article> comparator = Comparator.comparing(Article::getContributor);
// 投稿者名でソート
list.stream().sorted(comparator)
.forEach(a ->
System.out.println(a.getContributor() + " " + a.getDate() + " " + a.getGoodCount()));
Hanako 2017-02-05 53
Hanako 2016-11-01 160
Hanako 2012-08-20 22
Pochi 2013-03-16 38
Pochi 2011-09-25 200
Pochi 2018-04-13 10
Taro 2018-07-11 15
Taro 2015-11-01 53
Taro 2015-10-31 54
他の項目でもソート可能。
thenComparing
thenComparing (Java Platform SE 8)
比較条件をチェーンできるメソッド。
以下のように使用する。
Comparator.comparing(...).thenComparing(...).thenComparing(...);
前の条件が同じ(equals
)だった場合に、更に比較を行う。
辞書式順序コンパレータをもう一方のコンパレータとともに返します。
このComparatorで2つの要素が等しい(つまり、compare(a, b) == 0)と見なされる場合は、otherを使ってその順序が決められます。
複数項目でのソート
名前 -> 投稿日でソート
// Comparator作成
Comparator<Article> comparator =
Comparator.comparing(Article::getContributor).thenComparing(Article::getDate);
// ソート処理
list.stream().sorted(comparator)
.forEach(a ->
System.out.println(a.getContributor() + " " + a.getDate() + " " + a.getGoodCount()));
Hanako 2012-08-20 22
Hanako 2016-11-01 160
Hanako 2017-02-05 53
Pochi 2011-09-25 200
Pochi 2013-03-16 38
Pochi 2018-04-13 10
Taro 2015-10-31 54
Taro 2015-11-01 53
Taro 2018-07-11 15
名前 -> いいね数でソート
// Comparator作成
Comparator<Article> comparator =
Comparator.comparing(Article::getContributor).thenComparing(Article::getGoodCount);
// ソート処理
list.stream().sorted(comparator)
.forEach(a ->
System.out.println(a.getContributor() + " " + a.getDate() + " " + a.getGoodCount()));
Hanako 2012-08-20 22
Hanako 2017-02-05 53
Hanako 2016-11-01 160
Pochi 2018-04-13 10
Pochi 2013-03-16 38
Pochi 2011-09-25 200
Taro 2018-07-11 15
Taro 2015-11-01 53
Taro 2015-10-31 54
昇順にしたい場合は、reversed()
をつける
// Comparator作成
Comparator<Article> comparator =
Comparator.comparing(Article::getContributor).thenComparing(Article::getGoodCount).reversed();
// ソート処理
list.stream().sorted(comparator)
.forEach(a ->
System.out.println(a.getContributor() + " " + a.getDate() + " " + a.getGoodCount()));
Taro 2015-10-31 54
Taro 2015-11-01 53
Taro 2018-07-11 15
Pochi 2011-09-25 200
Pochi 2013-03-16 38
Pochi 2018-04-13 10
Hanako 2016-11-01 160
Hanako 2017-02-05 53
Hanako 2012-08-20 22
所感
- 複数条件でのソートは意外と楽だった
-
Stream
めちゃくちゃ便利(今更だけど) -
Comparator
の使い方はまだまだ学ぶ必要がありそう - 昇順・降順等を細かく指定したい場合は、
Comparator
自体を分けて複数回ソートした方が良さそう
参考
Stream (Java Platform SE 8 )
Comparator (Java Platform SE 8 )