如何将 Map.values 作为 Set 而不是 Collection?
How to get Map.values as a Set rather than a Collection?
我有一个映射 Map<String, SomeType>
,其中 SomeType
的每个实例都按名称添加,例如 map.put(object.getName(), object)
。最后,map.values()
.
没有重复
现在,我想要这张地图的 Set<SomeType>
而不是像 new HashSet<>(map.values())
这样的副本。
这可能吗,只对标准库有优惠?
没有 Collection
包装器是不可能的。
只是因为在您的情况下没有重复,并不意味着它们不能。
Java 集合 API 允许您在 Map
中放置重复值,因此合同必须 return Collection
而不是 Set
.
您已经知道如何使用 new HashSet<>(map.values())
。您无法直接获取一组值,因为这些值可能包含重复项。即使在您的特定 Map 中没有重复值,在一般 Map 中也可能存在重复值。
您可以使用 Java 8 个 Streams 做一些事情,但它与显式实例化 Set 相比没有任何优势。
Set<SomeType> values = map.values().stream().collect(Collectors.toSet());
创建任何 Collection
的 Set
视图将是一件简单的事情。
public final class SetView<E> extends AbstractSet<E> {
private final Collection<? extends E> collection;
private SetView(Collection<? extends E> collection) {
this.collection = collection;
}
public static <E> SetView<E> of(Collection<? extends E> collection) {
return new SetView<>(collection);
}
@Override
public boolean contains(Object e) {
return collection.contains(e);
}
// rest omitted.
}
有了这个,你就可以写 Set<E> set = SetView.of(map.values());
并且对 Map
的所有更改都会自动反映在 Set
.
中
这种方法的问题在于,如果不复制 Collection
,某些方法将难以实现。比如size()
怎么写?
最明智的做法是
@Override
public int size() {
return new HashSet<>(collection).size();
}
但这违背了使用视图而不是首先复制元素的目的。如果您知道 Collection
永远不会包含重复项,您 可以 简单地做
@Override
public int size() {
return collection.size();
}
但是我建议不要采用这种方法。 Map
允许包含重复值,添加两个具有相同值的条目的可能性意味着 Set
的合同将被破坏。
除非你有 非常 不想复制元素的充分理由,否则我只会使用 new HashSet<>(map.values())
.
我有一个映射 Map<String, SomeType>
,其中 SomeType
的每个实例都按名称添加,例如 map.put(object.getName(), object)
。最后,map.values()
.
现在,我想要这张地图的 Set<SomeType>
而不是像 new HashSet<>(map.values())
这样的副本。
这可能吗,只对标准库有优惠?
没有 Collection
包装器是不可能的。
只是因为在您的情况下没有重复,并不意味着它们不能。
Java 集合 API 允许您在 Map
中放置重复值,因此合同必须 return Collection
而不是 Set
.
您已经知道如何使用 new HashSet<>(map.values())
。您无法直接获取一组值,因为这些值可能包含重复项。即使在您的特定 Map 中没有重复值,在一般 Map 中也可能存在重复值。
您可以使用 Java 8 个 Streams 做一些事情,但它与显式实例化 Set 相比没有任何优势。
Set<SomeType> values = map.values().stream().collect(Collectors.toSet());
创建任何 Collection
的 Set
视图将是一件简单的事情。
public final class SetView<E> extends AbstractSet<E> {
private final Collection<? extends E> collection;
private SetView(Collection<? extends E> collection) {
this.collection = collection;
}
public static <E> SetView<E> of(Collection<? extends E> collection) {
return new SetView<>(collection);
}
@Override
public boolean contains(Object e) {
return collection.contains(e);
}
// rest omitted.
}
有了这个,你就可以写 Set<E> set = SetView.of(map.values());
并且对 Map
的所有更改都会自动反映在 Set
.
这种方法的问题在于,如果不复制 Collection
,某些方法将难以实现。比如size()
怎么写?
最明智的做法是
@Override
public int size() {
return new HashSet<>(collection).size();
}
但这违背了使用视图而不是首先复制元素的目的。如果您知道 Collection
永远不会包含重复项,您 可以 简单地做
@Override
public int size() {
return collection.size();
}
但是我建议不要采用这种方法。 Map
允许包含重复值,添加两个具有相同值的条目的可能性意味着 Set
的合同将被破坏。
除非你有 非常 不想复制元素的充分理由,否则我只会使用 new HashSet<>(map.values())
.