我是否需要自定义 Spliterator 以避免额外的 .stream() 调用?
我有这段代码可以正常工作,但我觉得它很难看.
I have this code which works fine, but I find it ugly.
@EqualsAndHashCode
public abstract class Actions {
@Getter
private List<ActionsBloc> blocs;
public Actions mergeWith(@NotNull Actions other) {
this.blocs = Stream.of(this.blocs, other.blocs)
.flatMap(Collection::stream)
.collect(groupingBy(ActionsBloc::getClass, reducing(ActionsBloc::mergeWith)))
.values()
.stream()
.filter(Optional::isPresent)
.map(Optional::get)
.collect(toList());
return this;
}
}
ActionsBloc
是一个超类型,其中包含 Action
列表.
ActionsBloc
is a super type which contains a list of Action
.
public interface ActionsBloc {
<T extends Action> List<T> actions();
default ActionsBloc mergeWith(ActionsBloc ab) {
this.actions().addAll(ab.actions());
return this;
}
}
我要做的是根据 Class
类型将 Actions
的 blocks
合并在一起.所以我按 ActionsBloc::getClass
分组,然后通过调用 ActionsBloc::mergeWith
进行合并.
What I want to do is merge blocs
of Actions
together based on the Class
type. So I'm grouping by ActionsBloc::getClass
and then merge by calling ActionsBloc::mergeWith
.
我觉得丑陋的是在 collect
上结束第一个流之后调用 values().stream()
.
What I find ugly is calling the values().stream()
after the first stream was ended on collect
.
有没有办法只对一个流进行操作并摆脱 values().stream()
,还是我必须编写一个自定义 Spliterator?换句话说,我的代码中只有一个 collect
.
Is there a way to operate only on one stream and get rid of values().stream()
, or do I have to write a custom Spliterator? In other words have only one collect
in my code.
推荐答案
您可以使用减少标识来解决这个问题.一种方法是将 mergeWith
的实现更新为:
You can work with a reducing identity to sort that out possibly. One way could be to update the implementation of mergeWith
as :
default ActionsBloc mergeWith(ActionsBloc ab) {
this.actions().addAll(Optional.ofNullable(ab)
.map(ActionsBloc::actions)
.orElse(Collections.emptyList()));
return this;
}
然后将grouping
和reduction
修改为:
this.blocs = new ArrayList<>(Stream.of(this.blocs, other.blocs)
.flatMap(Collection::stream)
.collect(groupingBy(ActionsBloc::getClass, reducing(null, ActionsBloc::mergeWith)))
.values());
Edit:正如 Holger 指出的那样,使用 groupingBy
和 reducing
的用例可以更合适地使用 toMap
为:
Edit: As Holger pointed out such use cases of using groupingBy
and reducing
further could be more appropriately implemented using toMap
as :
this.blocs = new ArrayList<>(Stream.concat(this.blocs.stream(), other.blocs.stream())
.collect(Collectors.toMap(ActionsBloc::getClass, Function.identity(), ActionsBloc::mergeWith))
.values());
相关文章