Java Map<;K、 V>;如果我的地图需要小而不是快,我应该使用吗?

Java Map<;K、 V>;如果我的地图需要小而不是快,我应该使用吗?,java,dictionary,collections,Java,Dictionary,Collections,我习惯在我的程序中使用HashMap,因为我知道它通常是最有效的(如果使用得当的话),并且可以轻松处理大型映射。我知道EnumMap,它对枚举键非常有用,但我经常生成一个小映射,它永远不会变大,很可能很快就会被丢弃,并且没有并发问题 HashMap对于这些小型、本地和临时用途来说是否过于复杂?在这些情况下,我是否可以使用另一个简单的实现 我想我正在寻找一个Map实现,它类似于ArrayList的List。它存在吗 在回答之后添加: 下面是一个场景,一个缓慢但非常简单的实现可能会更好——当我有很

我习惯在我的程序中使用
HashMap
,因为我知道它通常是最有效的(如果使用得当的话),并且可以轻松处理大型映射。我知道
EnumMap
,它对枚举键非常有用,但我经常生成一个小映射,它永远不会变大,很可能很快就会被丢弃,并且没有并发问题

HashMap
对于这些小型、本地和临时用途来说是否过于复杂?在这些情况下,我是否可以使用另一个简单的实现

我想我正在寻找一个
Map
实现,它类似于
ArrayList
List
。它存在吗


在回答之后添加:

下面是一个场景,一个缓慢但非常简单的实现可能会更好——当我有很多这样的
Map
s时。例如,假设我有大约一百万张这样的小地图,每一张都有少量(通常不到三个)的条目。我的参考率很低——也许在它们大部分时间被丢弃之前,我实际上并没有参考它们。
HashMap
仍然是他们的最佳选择吗

资源利用率不仅仅是速度——例如,我想要一些不会使堆大量碎片化并使GCs花费很长时间的东西

也许
HashMap
是正确的答案,但这不是过早优化的情况(或者至少可能不是)


经过深思熟虑后,后来又添加了:

我决定亲手编写自己的
SmallMap
。使用
AbstractMap
制作一个很容易。我还添加了几个构造函数,这样就可以从现有的
Map
构造
SmallMap

在此过程中,我必须决定如何表示
Entry
s,并为
entrySet
方法实现
SmallSet


我通过编码(和单元测试)学到了很多东西,我想分享一下,以防其他人需要。它在github上。

我认为这是过早的优化。你的记忆力有问题吗?创建过多映射导致的性能问题?如果不是,我认为HashMap很好

此外,看看API,我没有看到比
HashMap
更简单的东西


如果您有问题,您可以推出自己的Map实现,它具有非常简单的内部结构。但我怀疑您是否会比默认的Map实现做得更好,另外,您还有确保新类正常工作的开销。在这种情况下,您的设计可能会有问题。

HashMap可能是最轻量和最简单的集合


有时更有效的解决方案是使用POJO。e、 g.如果你的键是字段名和/或你的值是原语。

我同意@hvgotcodes的观点,这是过早的优化,但了解工具箱中的所有工具仍然很好

如果对映射中的内容进行大量迭代,LinkedHashMap通常比HashMap快得多,如果有许多线程同时处理映射,则ConcurrentHashMap通常是更好的选择。我不会担心任何地图实现对于小数据集来说效率低下。通常情况下,另一种情况是,如果哈希值不正确,或者由于某些原因导致其装载的存储桶太少,那么构造不正确的映射很容易在处理大量数据时变得效率低下


当然,也有一些情况下,HashMap毫无意义,比如,如果您有三个值,您将始终使用键0、1和2进行索引,但我假设您了解:-)

HashMap是一个不错的选择,因为它提供了平均大小写
O(1)
put和get。尽管与SortedMap实现(即TreeMap
O(log n)
put和get)一样,它不能保证排序,但如果您不需要排序,则HashMap会更好。

HashMap使用更多或更少的内存(创建时),这取决于您初始化它的方式:更多的存储桶意味着更多的内存使用,但对于大量项目,访问速度更快;如果您只需要少量的项目,您可以用一个较小的值对其进行初始化,这将产生较少的桶,但仍然很快(因为每个桶都会收到一些项目)。如果设置正确,就不会浪费内存(基本上是内存使用与速度的折衷)


至于堆碎片和GC循环浪费等等,Map实现对此无能为力;这一切都取决于你如何设置它。请理解,这与Java的实现无关,而是泛型(例如,在中)哈希表(而不是
哈希表
s)不能假设任何关于
EnumMap
does这样的键值是映射结构的最佳实现。

Java中没有标准的小型映射实现
HashMap
是最好、最灵活的
Map
实现之一,很难被击败。然而,在非常小的需求领域——堆使用率和构建速度至关重要——有可能做得更好

我已经在GitHub上实现了,以演示如何做到这一点。我想听听关于我是否成功的评论。我决不能肯定我有

虽然这里提供的答案有时是有用的,但总的来说,他们往往会误解这一点。无论如何,最终,回答我自己的问题对我来说比得到一个问题有用得多


这里的问题已经达到了目的,这就是为什么我“自己回答了它”。

有一种叫做AirConcurrentMap的替代方案,它比我找到的任何其他映射在1K条目以上的内存效率更高,并且在基于键的操作和存储方面比ConcurrentSkipListMap更快
static class ThreadedSummingVisitor<K> extends ThreadedMapVisitor<K, Long> {
    private long sum;
    // This is idiomatic
    long getSum(VisitableMap<K, Long> map) {
        sum = 0;
        map.getVisitable().visit(this);
        return sum;
    }

    @Override
    public void visit(Object k, Long v) {
        sum += ((Long)v).longValue();
    }

    @Override
    public ThreadedMapVisitor<K, Long> split() {
        return new ThreadedSummingVisitor<K>();
    }

    @Override
    public void merge(ThreadedMapVisitor<K, Long> visitor) {
        sum += ((ThreadedSummingVisitor<K>)visitor).sum;
    }
}
...
// The threaded summer can be re-used in one line now.
long sum = new ThreadedSummingVisitor().getSum((VisitableMap)map);
Map< DayOfWeek , Employee > dailyWorker = 
    Map.of(
        DayOfWeek.MONDAY , alice ,
        DayOfWeek.TUESDAY , bob ,
        DayOfWeek.WEDNESDAY , bob ,
        DayOfWeek.THURSDAY , alice ,
        DayOfWeek.FRIDAY , carol ,
        DayOfWeek.SATURDAY , carol ,
        DayOfWeek.SUNDAY , carol
    )
;