將List集合分成分組成map在工作中常常會(huì)遇到。這里我總結(jié)了兩種方式:Lambda表達(dá)式方式和傳統(tǒng)方式。
前期準(zhǔn)備
先創(chuàng)建一個(gè)User類,用于分類
class User{
private Integer age;
private String name;
public User(Integer age, String name) {
this.age = age;
this.name = name;
}
// 省略get、set方法
@Override
public String toString() {
return "User{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
測(cè)試類中寫個(gè)打印方法,一目了然就可以看到分組
void printMap(Map<Integer, List<User>> map){
for (Map.Entry<Integer, List<User>> entry : map.entrySet()) {
Integer key = entry.getKey();
List<User> value = entry.getValue();
System.out.println("key="+key+", value="+value);
}
}
實(shí)操
先在測(cè)試類中創(chuàng)建一個(gè)User集合并初始化
public class CommonTest {
private final List<User> list;
{
list = new ArrayList<>();
list.add(new User(16, "16_1"));
list.add(new User(16, "16_2"));
list.add(new User(16, "16_3"));
list.add(new User(12, "12_1"));
list.add(new User(12, "12_2"));
list.add(new User(12, "12_3"));
list.add(new User(14, "14_1"));
list.add(new User(14, "14_2"));
list.add(new User(14, "14_3"));
}
}
Lambda表達(dá)式方式
Lambda表達(dá)式主要用到的是Collectors#groupingBy和partitioningBy。二者又有所不同:
- groupingBy 可以將list按條件分成多組,返回的對(duì)象
Map<K, List<T>>形式 - partitioningBy 只能將list按條件分為兩組,返回的對(duì)象是
Map<Boolean, List<T>>形式
groupingBy分組
話不多說看代碼
@Test
public void testGroupingBy(){
Map<Integer, List<User>> map = list.stream()
.collect(Collectors.groupingBy(User::getAge));
printMap(map);
}
結(jié)果:
key=16, value=[User{age=16, name='16_1'}, User{age=16, name='16_2'}, User{age=16, name='16_3'}]
key=12, value=[User{age=12, name='12_1'}, User{age=12, name='12_2'}, User{age=12, name='12_3'}]
key=14, value=[User{age=14, name='14_1'}, User{age=14, name='14_2'}, User{age=14, name='14_3'}]
可以看到通過groupingBy只需一行代碼就將list分組成map。groupingBy除了可以分組以外還可以利用Collectors類的其他方法進(jìn)行統(tǒng)計(jì)或者也可以將value分組成其他集合類。
partitioningBy 分組
將user按照年齡分組
@Test
public void testPartitioningBy(){
Map<Boolean, List<User>> map = list.stream()
.collect(Collectors.partitioningBy(user -> user.getAge() >= 14));
for (Map.Entry<Boolean, List<User>> entry : map.entrySet()) {
Boolean key = entry.getKey();
List<User> value = entry.getValue();
System.out.println("key="+key+", value="+value);
}
}
結(jié)果:
key=false, value=[User{age=12, name='12_1'}, User{age=12, name='12_2'}, User{age=12, name='12_3'}]
key=true, value=[User{age=16, name='16_1'}, User{age=16, name='16_2'}, User{age=16, name='16_3'}, User{age=14, name='14_1'}, User{age=14, name='14_2'}, User{age=14, name='14_3'}]
通過partitioningBy將list分成了兩組,key是Boolean類型。所以partitioningBy的分組條件必須是一個(gè)Boolean類型的結(jié)果。
傳統(tǒng)方式
傳統(tǒng)方式就是自己去手動(dòng)地實(shí)現(xiàn)分組邏輯。傳統(tǒng)方式也是可以分為兩種方式的。
- 手動(dòng)創(chuàng)建Map對(duì)象
@Test
public void testMap(){
Map<Integer, List<User>> map = new HashMap<>();
for (User user : list) {
Integer age = user.getAge();
List<User> values = map.getOrDefault(age, new ArrayList<>());
values.add(user);
map.put(age, values);
}
printMap(map);
}
這種方式就是代碼量相對(duì)大一點(diǎn),但是同樣也能實(shí)現(xiàn)分組的效果
- 手動(dòng)創(chuàng)建一個(gè)MultiValueMap對(duì)象
這種方式跟上面那種手動(dòng)方式差不多,但是更簡(jiǎn)單一點(diǎn)。
@Test
public void testMultiValueMap(){
MultiValueMap<Integer, User> map = new LinkedMultiValueMap<>();
for (User user : list) {
Integer age = user.getAge();
map.add(age, user);
}
printMap(map);
}
類似MultiValueMap的工具類應(yīng)該也有很多,本文的MultiValueMap是org.springframework.util包下的一個(gè)工具類。MultiValueMap也是Map的實(shí)現(xiàn)類,但是限定了value必須是List集合。同時(shí)它又增加了自己的方法以實(shí)現(xiàn)value是List集合的形式。MultiValueMap實(shí)現(xiàn)類有好幾個(gè),要使用LinkedMultiValueMap才是我們要的list集合分組,添加value的時(shí)候用的是add方法而不是put方法。
總結(jié)
通過對(duì)比可以發(fā)現(xiàn)使用Lambda表達(dá)式的方式進(jìn)行分組代碼量更少一點(diǎn),但是要求對(duì)Lambda表達(dá)式要熟悉。根據(jù)業(yè)務(wù)可以使用groupingBy分多組,也可以使用partitioningBy分兩組。傳統(tǒng)方式一眼就能讓人看明白,可讀性更好,使用傳統(tǒng)方式的話優(yōu)先還是選擇MultiValueMap更為簡(jiǎn)單。
喜歡的話,點(diǎn)個(gè)關(guān)注,給個(gè)贊吧