我测试了HashMap retainAll方法,以测试哪个方法使用JMH更快.

两个Hashmap A、B

  • 尺寸:A&>B,A:300~400,B:100~200
  • 大多数B元素都在A中,所以B-A大约是10~20,非常小

测试:获取两个HashMap的交集

  1. A.keySet().保留(B.keySet())

  2. B.keySet()

//JMH 
@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@Fork(value = 1, jvmArgs={"-Xms4G", "-Xmx4G"})
@Warmup(iterations = 5, time = 5)
@Measurement(iterations = 10, time = 5)

private Map<String, MyClass> bigOne, smallOne;

private final int testIteration = 1000;

@Benchmark
public void smallToBig(){
    for(int i=0;i<testIteration;i++){
        smallOne.keySet().retainAll(bigOne.keySet());
    }
}

@Benchmark
public void bigToSmall(){
    for(int i=0;i<testIteration;i++){
        bigOne.keySet().retainAll(smallOne.keySet());
    }
}

RetainAll方法使用AbstractMap中的CONTAINS,因此HashMap CONTAINS为O(1).因此迭代映射将占用大部分性能,这意味着小一次迭代应该更快.

我原以为前者会更快,但实际结果却不同

Result

我试了很多次,但还是得到了同样的结果.你能告诉我为什么Big.retainAll(小)更快吗?

谢谢你的帮助.

推荐答案

contains的平均复杂度为O(1),最差情况为O(N). 编辑:在Java 8之后的最坏情况下是O(Logn)!

对于Big.retainAll(Small)美元,你在一小集上做"包含",在大集上做许多删除.对于Small.retainAll(Big),你确实包含在一个更大的集合上,几乎没有go 掉u,说.(无论如何,删除肯定比包含复杂得多).

因此,如果您的基准测试是正确的,这可能意味着您的包含复杂性更接近O(N),这就是SmallToBig需要更多时间的原因.try 一些不同的键,例如Integer,看看是否会发生相同的情况

Java相关问答推荐

是否需要关闭Executors返回的执行器.newVirtualThreadPerTaskExecutor()?

强制Mockito返回null而不是emtpy list

Springdoc Whitelabel Error Page with Spring V3

如何在返回bigint []值的子查询中使用any?

ApachePOI:不带换行的新行

为什么我要创建一个单独的互斥体/锁对象?

确定Java中Math.Ranb()输出的上限

对某一Hyroby控制器禁用@cacheable

如何判断一个矩阵是否为有框矩阵?

为什么一个Test的instance?& gt;在构造函数中接受非空对象?

由于 list 中的权限错误,Android未生成

Arrays.hashcode(int[])为不同的元素提供相同的散列

将Spring Boot 3.2.0升级到3.2.1后查询执行错误

如何在不删除Java中已有内容的情况下覆盖文件内容?

支持MySQL 5.6的最新Hibernate版本

在Java中将.GRF转换为图像文件

JavaFX复杂项目体系 struct

如何通过gradle命令行从build.gradle获得Java targetCompatibility

spring 更新多项管理关系

Spring Boot Security-每个端点都被403禁止,Spring记录一个BasicErrorController#错误(HttpServlet请求)