简体   繁体   English

java.util.Map values()方法的性能

[英]java.util.Map values() method performance

I have a map like this with several million entries: 我有一张这样的地图,其中包含几百万个条目:

private final Map<String, SomeItem> tops = new HashMap<>();

I need to get list of values, which could be done by calling java.util.Map values() method. 我需要获取值列表,这可以通过调用java.util.Map values()方法来完成。

The question : 问题

Collection of values is created each time when I call this method or it is pre-computed and it is save from performance perspective to call it several times ? 每次我调用此方法时都会创建值集合,或者它是预先计算的,从性能角度来看,它可以保存多次以进行调用?

The issue is that in my case Map has several millions elements and I do not want to create new list each time values() is called 问题是在我的情况下Map有数百万个元素,并且我不想每次调用values()都创建新列表

Below is the copied implementation of Map.values() in java.util.HashMap : 以下是java.util.HashMapMap.values()的复制实现:

public Collection<V> values() {
    Collection<V> vs = values;
    if (vs == null) {
        vs = new Values();
        values = vs;
    }
    return vs;
}

This clearly shows that the value collection isn't created unless necessary. 这清楚地表明,除非有必要,否则不会创建值集合。 So, there should not be additional overhead caused by calls to values() 因此,不应因调用values()而造成额外的开销

One important point here may be: It does not matter! 这里重要的一点可能是: 没关系!


But first, referring to the other answers so far: The collection that is returned there is usually "cached", in that it is lazily created, and afterwards, the same instance will be returned. 但是首先,请参考到目前为止的其他答案:在这里返回的集合通常是“缓存的”,因为它是惰性创建的,然后,将返回相同的实例。 For example, considering the implementation in the HashMap class: 例如,考虑HashMap类中的实现:

public Collection<V> values() {
    Collection<V> vs;
    return (vs = values) == null ? (values = new Values()) : vs;
}

This is even specified (as part of the contract, as an implementation specification) in the documentation of the AbstractMap class (which most Map implementations are based on) : 甚至AbstractMap文档 (大多数Map实现基于该文档 )中指定了(作为合同的一部分,作为实现规范):

The collection is created the first time this method is called, and returned in response to all subsequent calls. 该集合是在第一次调用此方法时创建的,并响应于所有后续调用而返回。 No synchronization is performed, so there is a slight chance that multiple calls to this method will not all return the same collection. 没有执行同步,因此有几次机会对该方法的多次调用不会全部返回相同的集合。


But now, one could argue that the implementation might change later. 但是现在,有人可能会说实施可能会在以后更改。 The implementation of the HashMap class could change, or one might switch to another Map implementation that does not extend AbstractMap , and which is implemented differently. HashMap类的实现可以更改,或者可以切换到另一种不扩展AbstractMap且以不同方式实现的Map实现。 The fact that it is currently implemented like this is (for itself) no guarantee that it will always be implemented like this. 当前这样实现的事实本身(本身)并不能保证它总是这样实现。

So the more important point (and the reason why it does not matter ) is that the values() method is indeed supposed to return a collection view . 因此,更重要的一点(以及无关紧要的原因)是, values()方法确实应该返回一个集合视图 As stated in the documentation of the Map interface : Map接口文档中所述

The Map interface provides three collection views , which allow a map's contents to be viewed as a set of keys, collection of values, or set of key-value mappings. Map界面提供了三个集合视图 ,这些视图允许将地图的内容作为一组键,一组值或一组键-值映射来查看。

and specifically, the documentation of the Map#values() method : 特别Map#values()方法文档

Returns a Collection view of the values contained in this map. 返回此映射中包含的值的Collection视图。 The collection is backed by the map, so changes to the map are reflected in the collection, and vice-versa. 集合由地图支持,因此对地图的更改会反映在集合中,反之亦然。

I cannot imagine a reasonable way of implementing such a view that involves processing all values of the Map . 我无法想象实现包含处理Map所有值的视图的合理方法。


So for example, imagine the implementation in HashMap was like this: 例如,假设HashMap中的实现是这样的:

public Collection<V> values() {
    return new Values();
}

Then it would return a new collection each time that it was called. 然后,它将在每次调用时返回一个新的集合。 But creating this collection does not involve processing the values at all. 但是创建此集合根本涉及处理值。

Or to put it that way: The cost of calling this method is independent of the size of the map. 或这样说:调用此方法的成本与地图的大小无关 It basically has the cost of a single object creation, regardless of whether the map contains 10 or 10000 elements. 无论地图包含10个元素还是10000个元素,它基本上都需要创建单个对象。

As others have mentioned you can see this by looking at the code. 正如其他人提到的那样,您可以通过查看代码来看到这一点。 You can also code up a quick example to prove it to yourself. 您还可以编写一个快速示例来向自己证明。 The code below will print true 10 times as the object identity will always be the same for values. 下面的代码将打印正确的10次,因为对象标识的值始终相同。

public static void main(String[] args) {
    Map<String, String> myMap = new HashMap();
    Collection<String> lastValues = myMap.values();
    for (int i=0; i < 10; i++) {
        System.out.println(lastValues == myMap.values());
        lastValues = myMap.values();
    }
}

The following code will print true the first time and then false the next 9 times. 下面的代码将在第一次打印true,然后在接下来的9次false。

public static void main(String[] args) {
    Map<String, String> myMap = new HashMap();
    Collection<String> lastValues = myMap.values();
    for (int i=0; i < 10; i++) {
        System.out.println(lastValues == myMap.values());
        lastValues = myMap.values();
        myMap = new HashMap();
    }
}

One more suggestion after reading this thread, if the Map tops declared contents are not changed - you could use google guava ImmutableMap object. 阅读此主题后,还有一个建议,如果Map顶部声明的内容未更改-您可以使用google guava ImmutableMap对象。 For more info- UnmodifiableMap (Java Collections) vs ImmutableMap (Google) 有关更多信息-UnmodifiableMap(Java Collections)与ImmutableMap(Google)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM