Java Stream分组需求:按母亲姓名分组,以Name为Map键
解决方案:按MotherName分组并以Name为键的Map
这个问题我之前也碰到过,核心是要保持按母亲名字分组的逻辑不变,但把分组结果的键从String换成Name对象。这里分两种常见场景给出实现方式:
场景1:仅以MotherName作为分组判断依据(忽略Name的其他字段)
如果只要母亲名字相同,就归为同一组,且组的键是一个仅包含该母亲名字的Name实例,你需要先修改Name类,确保它的equals()和hashCode()只基于motherName字段(因为HashMap依赖这两个方法判断键是否相等),再调整分组逻辑:
第一步:修改Name类
import java.util.Objects; public class Name { private String name; private String fatherName; private String motherName; // 原有构造方法、getter/setter省略 // 新增静态工厂方法,快速创建仅含motherName的Name实例 public static Name fromMotherName(String motherName) { Name nameInstance = new Name(); nameInstance.setMotherName(motherName); return nameInstance; } // 重写equals,仅比较motherName @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Name name = (Name) o; return Objects.equals(motherName, name.motherName); } // 重写hashCode,仅基于motherName @Override public int hashCode() { return Objects.hash(motherName); } }
第二步:调整分组代码
import java.util.Collection; import java.util.List; import java.util.Map; import java.util.stream.Collectors; Collection<Person> persons = ...; // 你的Person集合 Map<Name, List<Person>> group = persons.stream() .collect(Collectors.groupingBy( // 分组函数返回Name对象,而非字符串 person -> Name.fromMotherName(person.getName().getMotherName()) ));
场景2:以MotherName分组,但键保留组内第一个Person的完整Name对象
如果你希望组的键是该分组下第一个出现的Person的完整Name实例(保留name、fatherName等所有字段),可以先按motherName字符串分组,再转换键的类型:
import java.util.AbstractMap; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.stream.Collectors; Collection<Person> persons = ...; // 你的Person集合 Map<Name, List<Person>> group = persons.stream() // 先按motherName字符串分组,同时把每组转换成<Name, List<Person>>的Entry .collect(Collectors.groupingBy( p -> p.getName().getMotherName(), Collectors.collectingAndThen( Collectors.toList(), personList -> new AbstractMap.SimpleEntry<>( personList.get(0).getName(), // 取第一个Person的Name作为键 personList ) ) )) // 把Entry集合转换成最终的Map .values() .stream() .collect(Collectors.toMap( AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue ));
注意事项
- 场景2中如果分组后的列表为空(实际Stream分组不会出现),
personList.get(0)会抛出IndexOutOfBoundsException,可以加个非空判断。 - 如果你的
Name类已经有合理的equals()和hashCode()实现(比如比较所有字段),那场景1的修改不适用,需要用场景2的方式。
内容的提问来源于stack exchange,提问作者Jordi
相关产品推荐
相关产品推荐

