提问人:Scroobius 提问时间:11/13/2023 最后编辑:Scroobius 更新时间:11/14/2023 访问量:64
如何基于谓词创建实时子集合?
How can I create a live sub-collection based on a predicate?
问:
背景
我有一个界面
public interface ThingRegistry {
public Set<Thing> getAllThings();
public Set<Thing> getAllThingsWithProperty(String property);
}
和实现
public class MemoryThingRegistry {
private final Set<Thing> things = new HashSet<>();
public Set<Thing> getAllThings() {
return Collections.unmodifiableSet(this.things);
}
public Set<Thing> getAllThingsWithProperty(final String property) {
return this.things.stream().filter((thing) -> thing.hasProperty(property)).collect(Collectors.toUnmodifiableSet());
}
}
问题
- 返回的 Set 将反映在我的注册表中所做的任何更改
getAllThings()
- 但是,返回的 Set 不会反映这些更改
getAllThingsWithProperty()
问题
有没有办法使用标准的 java 库,或一些非常常见的第三方库,使返回值成为“实时”子?即它由原始文件“支持”,但每次访问时都会重新应用?最好是可以应用于任何的东西,因为我有另一个使用 .getAllThingsWithProperty()
Set
Set
Predicate
Collection
List
我知道我可以编写自己的实现,但宁愿避免这种情况。Set
答:
而不是返回 .您可以编写一个返回 .每次你想得到电流时,你调用那个 的方法。Set<Thing>
Supplier<Set<Thing>>
Set
Supplier
get()
public Supplier<Set<Thing>> getAllThingsWithProperty(final String property) {
return () -> this.things.stream().filter((thing) -> thing.hasProperty(property)).collect(Collectors.toSet());
}
用它来提出一个实现是相当简单的。您需要做的就是实现 and 方法。您已经在使用流,因此您可以使用流来实现以下方法:AbstractSet
Set
size
iterator
public static <E> Set<E> filteredSet(Set<E> set, Predicate<? super E> pred) {
return new AbstractSet<>() {
public int size() {
return (int) set.stream().filter(pred).count();
}
public Iterator<E> iterator() {
return set.stream().filter(pred).iterator();
}
};
}
这是一个功能齐全的只读 .它提供了后备集的“实时视图”,因为它的元素在每次操作时都会被流式处理和过滤。Set
这对于元素数量较少的集合是可行的,但随着元素数量的增加,它可能会明显减慢。例如,该方法可能会迭代整个集合,因此为 O(N)。可以重写该方法以直接委托给后备集。这将把时间复杂度降低到基础集合提供的任何内容 -- 因为 这是 O(1) -- 但其中涉及一些微妙之处。contains
contains
HashSet
若要使集合读写,需要实现该方法并重新实现迭代器,以便它支持该方法。但是你首先返回的是不可修改的集合,所以也许你不需要它。add
remove
如果你需要用 做类似的事情,请看一下。这相当简单。或者用于包装任何集合,方式与此处所示的相同。List
AbstractList
AbstractCollection
AbstractSet
评论
@Override @SuppressWarnings("unchecked") public boolean contains(Object o) { return set.contains(o) && pred.test((E)o); }
set.contains(o)
List
AbstractSequentialList
评论
Set