Java 8 个按可选属性分组的流
Java 8 Streams Grouping by an Optional Attribute
我正在尝试对来自属性的计算值进行分组。计算值是可选的 - 更清楚一点,他是一个简化的例子:
class Foo:
int id;
Group group;
.. some other stuff
class Group:
String groupId;
... (some other stuff)
class SomeName:
String someAttribute;
class Converter:
public Optional<SomeName> getSomenameFromGroup(Group)
我无法更改 Converter 中的方法,因为它不属于我。
我有一个 Foo 列表,我想按 SomeName 的 "someAttribute" 进行过滤。
例如,我有这样的东西:
Map<String, List<Foo>> fooBySomeName =
fooList.stream().collect(Collectors
.groupingBy(foo -> {
Optional<SomeName> name =
converter.getSomenameFromGroup(foo.getGroup.getGroupId());
return name.isPresent() ? name.get().someAttribute() : "";
}));
但问题是,如果名称不在 groupingBy 语句中,我不想在我的地图中添加任何内容。我有这样的事情:
fooBySomeNames.remove("")
我认为这可以从地图中删除按该键分组的任何内容,但是在 groupingBy 语句中是否有更清晰或更正确的方法来执行此操作?
您可以使用过滤器删除条目,如下所示。
Map<String, List<Foo>> fooBySomeName = fooList.stream()
.filter(foo -> fooToSomeAttribute(foo).isPresent())
.collect(Collectors.groupingBy(foo -> fooToSomeAttribute(foo).get()));
private static Optional<String> fooToSomeAttribute(Foo foo)
{
return Optional.ofNullable(foo)
.map(Foo::getGroup)
.flatMap(new Converter()::getSomenameFromGroup)
.map(SomeName::getSomeAttribute);
}
或者,使用 pair 对象,您可以避免对每个 Foo 的 someAttribute 进行双重计算:
Map<String, List<Foo>> fooBySomeName = fooList.stream()
.filter(Objects::nonNull)
.map(FooAndSomeAttribute::new)
.filter(pair -> pair.getSomeAttribute().isPresent())
.collect(Collectors.groupingBy(
pair -> pair.getSomeAttribute().get(),
Collectors.mapping(
FooAndSomeAttribute::getFoo,
Collectors.toList())));
private static class FooAndSomeAttribute
{
private final Foo foo;
private final Optional<String> someAttribute;
public FooAndSomeAttribute(Foo foo)
{
this.foo = foo;
this.someAttribute = Optional.ofNullable(foo)
.map(Foo::getGroup)
.flatMap(new Converter()::getSomenameFromGroup)
.map(SomeName::getSomeAttribute);
}
public Foo getFoo()
{
return foo;
}
public Optional<String> getSomeAttribute()
{
return someAttribute;
}
}
我正在尝试对来自属性的计算值进行分组。计算值是可选的 - 更清楚一点,他是一个简化的例子:
class Foo:
int id;
Group group;
.. some other stuff
class Group:
String groupId;
... (some other stuff)
class SomeName:
String someAttribute;
class Converter:
public Optional<SomeName> getSomenameFromGroup(Group)
我无法更改 Converter 中的方法,因为它不属于我。
我有一个 Foo 列表,我想按 SomeName 的 "someAttribute" 进行过滤。
例如,我有这样的东西:
Map<String, List<Foo>> fooBySomeName =
fooList.stream().collect(Collectors
.groupingBy(foo -> {
Optional<SomeName> name =
converter.getSomenameFromGroup(foo.getGroup.getGroupId());
return name.isPresent() ? name.get().someAttribute() : "";
}));
但问题是,如果名称不在 groupingBy 语句中,我不想在我的地图中添加任何内容。我有这样的事情:
fooBySomeNames.remove("")
我认为这可以从地图中删除按该键分组的任何内容,但是在 groupingBy 语句中是否有更清晰或更正确的方法来执行此操作?
您可以使用过滤器删除条目,如下所示。
Map<String, List<Foo>> fooBySomeName = fooList.stream()
.filter(foo -> fooToSomeAttribute(foo).isPresent())
.collect(Collectors.groupingBy(foo -> fooToSomeAttribute(foo).get()));
private static Optional<String> fooToSomeAttribute(Foo foo)
{
return Optional.ofNullable(foo)
.map(Foo::getGroup)
.flatMap(new Converter()::getSomenameFromGroup)
.map(SomeName::getSomeAttribute);
}
或者,使用 pair 对象,您可以避免对每个 Foo 的 someAttribute 进行双重计算:
Map<String, List<Foo>> fooBySomeName = fooList.stream()
.filter(Objects::nonNull)
.map(FooAndSomeAttribute::new)
.filter(pair -> pair.getSomeAttribute().isPresent())
.collect(Collectors.groupingBy(
pair -> pair.getSomeAttribute().get(),
Collectors.mapping(
FooAndSomeAttribute::getFoo,
Collectors.toList())));
private static class FooAndSomeAttribute
{
private final Foo foo;
private final Optional<String> someAttribute;
public FooAndSomeAttribute(Foo foo)
{
this.foo = foo;
this.someAttribute = Optional.ofNullable(foo)
.map(Foo::getGroup)
.flatMap(new Converter()::getSomenameFromGroup)
.map(SomeName::getSomeAttribute);
}
public Foo getFoo()
{
return foo;
}
public Optional<String> getSomeAttribute()
{
return someAttribute;
}
}