Jot*_*edo 5 java collections lambda java-8 java-stream
我有以下函数来统一多个集合(包括重复的元素):
public static <T> List<T> unify(Collection<T>... collections) {
return Arrays.stream(collections)
.flatMap(Collection::stream)
.collect(Collectors.toList());
}
Run Code Online (Sandbox Code Playgroud)
如果函数具有类似的集合交集(使用类型相等),那将是很好的.例如:
public static <T> List<T> intersect(Collection<T>... collections) {
//Here is where the magic happens
}
Run Code Online (Sandbox Code Playgroud)
我发现了交叉函数的一个实现,但它不使用流:
public static <T> Set<T> intersect(Collection<? extends Collection<T>> collections) {
Set<T> common = new LinkedHashSet<T>();
if (!collections.isEmpty()) {
Iterator<? extends Collection<T>> iterator = collections.iterator();
common.addAll(iterator.next());
while (iterator.hasNext()) {
common.retainAll(iterator.next());
}
}
return common;
}
Run Code Online (Sandbox Code Playgroud)
有没有办法实现类似于使用流的统一函数?我在java8/stream api中没那么有经验,因为一些建议会非常有用.
Tag*_*eev 10
您可以在某个实用程序类中编写自己的收集器并使用它:
public static <T, S extends Collection<T>> Collector<S, ?, Set<T>> intersecting() {
class Acc {
Set<T> result;
void accept(S s) {
if(result == null) result = new HashSet<>(s);
else result.retainAll(s);
}
Acc combine(Acc other) {
if(result == null) return other;
if(other.result != null) result.retainAll(other.result);
return this;
}
}
return Collector.of(Acc::new, Acc::accept, Acc::combine,
acc -> acc.result == null ? Collections.emptySet() : acc.result,
Collector.Characteristics.UNORDERED);
}
Run Code Online (Sandbox Code Playgroud)
用法非常简单:
Set<T> result = Arrays.stream(collections).collect(MyCollectors.intersecting());
Run Code Online (Sandbox Code Playgroud)
但请注意,收集器不能短路:即使中间结果是空集合,它仍将处理流的其余部分.
这样的收集器可以在我的免费StreamEx库中找到(参见参考资料MoreCollectors.intersecting()).它适用于像上面这样的普通流,但如果你将它与StreamEx(扩展普通流)一起使用,它就会变成短路:处理实际上可能会提前停止.