您还可以使用中间 Map 和一个键,该键聚合来自 Foo 类的字段 a、b 和 c 以及收集所有 d 字段值的 List<Integer> 值。在下面例如,我创建了 MapKey 类 - 一个聚合这些字段并实现 hashCode 和 equals 方法的辅助类,因此它可以用作 HashMap 中的键。
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class FooMain {
public static void main(String[] args) {
final DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("MM/dd/yyyy");
final List<Foo> foos = Arrays.asList(
new Foo("Test", "Test", LocalDate.parse("10/02/2015", dateFormat), 5),
new Foo("Test", "Test", LocalDate.parse("10/02/2015", dateFormat), 4),
new Foo("Test", "Test", LocalDate.parse("10/02/2015", dateFormat), 3),
new Foo("Test", "Test", LocalDate.parse("02/02/2015", dateFormat), 5),
new Foo("Test", "Potato", LocalDate.parse("02/02/2015", dateFormat), 5)
);
List<FooResult> result = foos.stream()
.collect(Collectors.groupingBy(foo -> new MapKey(foo.a, foo.b, foo.c), Collectors.mapping(Foo::getD, Collectors.toList())))
.entrySet()
.stream()
.map(entry -> new FooResult(entry.getKey().a, entry.getKey().b, entry.getKey().c, entry.getValue()))
.collect(Collectors.toList());
result.forEach(System.out::println);
}
public static final class Foo {
private final String a;
private final String b;
private final LocalDate c;
private final int d;
Foo(String a, String b, LocalDate c, int d) {
this.a = a;
this.b = b;
this.c = c;
this.d = d;
}
int getD() {
return d;
}
}
public static final class FooResult {
private final String a;
private final String b;
private final LocalDate c;
private final List<Integer> d;
FooResult(String a, String b, LocalDate c, List<Integer> d) {
this.a = a;
this.b = b;
this.c = c;
this.d = d;
}
@Override
public String toString() {
return "FooResult{" +
"a='" + a + '\'' +
", b='" + b + '\'' +
", c=" + c +
", d=" + d +
'}';
}
}
public static final class MapKey {
private final String a;
private final String b;
private final LocalDate c;
MapKey(String a, String b, LocalDate c) {
this.a = a;
this.b = b;
this.c = c;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof MapKey)) return false;
MapKey mapKey = (MapKey) o;
if (a != null ? !a.equals(mapKey.a) : mapKey.a != null) return false;
if (b != null ? !b.equals(mapKey.b) : mapKey.b != null) return false;
return c != null ? c.equals(mapKey.c) : mapKey.c == null;
}
@Override
public int hashCode() {
int result = a != null ? a.hashCode() : 0;
result = 31 * result + (b != null ? b.hashCode() : 0);
result = 31 * result + (c != null ? c.hashCode() : 0);
return result;
}
}
}
然后你可以看到你可以做你的转换是 6 行代码。该程序的输出如下:
FooResult{a='Test', b='Potato', c=2015-02-02, d=[5]}
FooResult{a='Test', b='Test', c=2015-02-02, d=[5]}
FooResult{a='Test', b='Test', c=2015-10-02, d=[5, 4, 3]}
我还使Foo、FooResult 和MapKey 不可变——当您必须处理流转换时,这始终是一个不错的选择。您不希望在流操作期间产生任何副作用,不可变对象可以保证这一点。