はじめに
以下のような Item を top -> middle -> bottom の順序でソートしたい。
List<Item> list = Arrays.asList(
new Item(1, "bottom"),
new Item(2, "top"),
new Item(3, "middle"),
new Item(4, "top"));
第2ソートキーを id とすると、Guava では ComparisonChain で Ordering.explicit() を指定することとなる。
ComparisonChain.start()
.compare(o1.getName(), o2.getName(), Ordering.explicit(priorities).nullsLast())
.compare(o1.getId(), o2.getId(), Ordering.natural().nullsLast())
.result();
Java8 Stream での任意順序ソート
Java8 Stream では、Ordering.explicit() に相当するものは無いので、以下のようにする。
List<String> priorities = Arrays.asList("top", "middle", "bottom"); List<Item> sorted = list.stream() .sorted(Comparator .comparing((Item item) -> priorities.indexOf(item.getName())) .thenComparing(Item::getId)) .collect(Collectors.toList());
以下のように並び替えることができる。
Item {2, 'top'}, Item {4, 'top'}, Item {3, 'middle'}, Item {1, 'bottom'}
未知のキーを末尾に持ってくる
前述のソートだと、new Item(5, "?") であったり new Item(6, null) のような、未知キーが先頭にきてしまう。
その場合は、逆順でソートした方がよい。
List<String> priorities = Arrays.asList("top", "middle", "bottom"); Collections.reverse(priorities); List<Item> sorted = list.stream() .sorted(Comparator .comparing((Item item) -> priorities.indexOf(item.getName()), Comparator.reverseOrder()) .thenComparing(Item::getId)) .collect(Collectors.toList());
以下のような並びになる。
Item {2, 'top'}, Item {4, 'top'}, Item {3, 'middle'}, Item {1, 'bottom'}, Item {5, '?'}, Item {6, null}

