假设我有一个班级
Class Person {
String name;
String uid;
String phone;
}
我试图按班级的所有领域进行分组。如何在JAVA 8中使用并行流转换a
List<Person> into Map<String,Set<Person>>
其中地图的关键字是类中每个字段的值。 JAVA 8以下示例组由单个字段组成,如何才能将一个类的所有字段组成一个Map?
ConcurrentMap<Person.Sex, List<Person>> byGender =
roster
.parallelStream()
.collect(
Collectors.groupingByConcurrent(Person::getGender));
您可以使用of
中的Collector
静态工厂方法来实现:
Map<String, Set<Person>> groupBy = persons.parallelStream()
.collect(Collector.of(
ConcurrentHashMap::new,
( map, person ) -> {
map.computeIfAbsent(person.name, k -> new HashSet<>()).add(person);
map.computeIfAbsent(person.uid, k -> new HashSet<>()).add(person);
map.computeIfAbsent(person.phone, k -> new HashSet<>()).add(person);
},
( a, b ) -> {
b.forEach(( key, set ) -> a.computeIfAbsent(key, k -> new HashSet<>()).addAll(set));
return a;
}
));
正如Holger在评论中所建议的那样,以下方法可优先于上述方法:
Map<String, Set<Person>> groupBy = persons.parallelStream()
.collect(HashMap::new, (m, p) -> {
m.computeIfAbsent(p.name, k -> new HashSet<>()).add(p);
m.computeIfAbsent(p.uid, k -> new HashSet<>()).add(p);
m.computeIfAbsent(p.phone, k -> new HashSet<>()).add(p);
}, (a, b) -> b.forEach((key, set) -> {
a.computeIfAbsent(key, k -> new HashSet<>()).addAll(set));
});
它使用重载的collect
方法,该方法与我上面建议的语句相同。
您可以链接您的分组收集器,这将为您提供多级地图。但是,如果您想要分组超过2个字段,这并不理想。
更好的选择是覆盖equals
类中的hashcode
和Person
方法,以定义两个给定对象的相等性,在这种情况下将是所有所述字段。然后你可以通过Person
分组,即groupingByConcurrent(Function.identity())
,在这种情况下,你最终会得到:
ConcurrentMap<Person, List<Person>> resultSet = ....
例:
class Person {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
if (name != null ? !name.equals(person.name) : person.name != null) return false;
if (uid != null ? !uid.equals(person.uid) : person.uid != null) return false;
return phone != null ? phone.equals(person.phone) : person.phone == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + (uid != null ? uid.hashCode() : 0);
result = 31 * result + (phone != null ? phone.hashCode() : 0);
return result;
}
private String name;
private String uid; // these should be private, don't expose
private String phone;
// getters where necessary
// setters where necessary
}
然后:
ConcurrentMap<Person, List<Person>> resultSet = list.parallelStream()
.collect(Collectors.groupingByConcurrent(Function.identity()));