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实现(即TreeMapO(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
)
;