To prove the point, here is the jmh test, which searches for a record on cards containing records 10, 10_000 and 10_000_000 . The results show that the search for constant is O (1). The problem is elsewhere in your code. Even if you do not understand the code, the results are just readable numbers (see the end).
import java.math.BigDecimal; import java.math.RoundingMode; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.Level; import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.TearDown; import org.openjdk.jmh.annotations.Warmup; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; import javafx.geometry.Point2D; @BenchmarkMode(org.openjdk.jmh.annotations.Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) @Warmup(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS) @Measurement(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS) public class TwoMapsTest { public static void main(String[] args) throws RunnerException { Options opt = new OptionsBuilder().include(EightMillionsTest.class.getSimpleName()) .jvmArgs("-ea", "-Xms10g", "-Xmx10g") .shouldFailOnError(true) .build(); new Runner(opt).run(); } // the check bellow assert map.size() == numberOfElements; can absolutely fail // fingers crossed that it does not. @State(Scope.Thread) public static class Map_10 { int numberOfElements = 10; public Map<Point2D, Integer> map = new HashMap<>(); public Point2D mightBePresent = null; public Point2D isPresent = null; @Setup(Level.Iteration) public void setUp() { int randomInsideHowManyBoundry = ThreadLocalRandom.current().nextInt(numberOfElements); for (int i = 0; i < numberOfElements; ++i) { double[] d = generateTwoPoints(-3.0, 3.9999, 4); Point2D p = new Point2D(d[0], d[1]); if (isPresent == null && i == randomInsideHowManyBoundry) { isPresent = new Point2D(d[0], d[1]); } map.put(p, i); } assert map.containsKey(isPresent); assert map.size() == numberOfElements; } @TearDown(Level.Iteration) public void tearDown() { map.clear(); } } @State(Scope.Thread) public static class Map_10_000 { int numberOfElements = 10_000; public Map<Point2D, Integer> map = new HashMap<>(); public Point2D mightBePresent = null; public Point2D isPresent = null; @Setup(Level.Iteration) public void setUp() { int randomInsideHowManyBoundry = ThreadLocalRandom.current().nextInt(numberOfElements); for (int i = 0; i < numberOfElements; ++i) { double[] d = generateTwoPoints(-3.0, 3.9999, 4); Point2D p = new Point2D(d[0], d[1]); if (isPresent == null && i == randomInsideHowManyBoundry) { isPresent = new Point2D(d[0], d[1]); } map.put(p, i); } assert map.containsKey(isPresent); assert map.size() == numberOfElements; } @TearDown(Level.Iteration) public void tearDown() { map.clear(); } } @State(Scope.Thread) public static class Map_10_000_000 { int numberOfElements = 10_000_000; public Map<Point2D, Integer> map = new HashMap<>(); public Point2D mightBePresent = null; public Point2D isPresent = null; @Setup(Level.Iteration) public void setUp() { int randomInsideHowManyBoundry = ThreadLocalRandom.current().nextInt(10_000_000); for (int i = 0; i < 10_000_000; ++i) { double[] d = generateTwoPoints(-3.0, 3.9999, 4); Point2D p = new Point2D(d[0], d[1]); if (isPresent == null && i == randomInsideHowManyBoundry) { isPresent = new Point2D(d[0], d[1]); } map.put(p, i); } assert map.containsKey(isPresent); assert map.size() == numberOfElements; } @TearDown(Level.Iteration) public void tearDown() { map.clear(); } } @Fork(1) @Benchmark public int mightBePresentMap_10(Map_10 map) { Integer x = map.map.get(map.mightBePresent); return x == null ? -1 : x; } @Fork(1) @Benchmark public int isPresentMap_10(Map_10 map) { Integer x = map.map.get(map.isPresent); return x == null ? -1 : x; } @Fork(1) @Benchmark public int mightBePresentMap_10_000(Map_10_000 map) { Integer x = map.map.get(map.mightBePresent); return x == null ? -1 : x; } @Fork(1) @Benchmark public int isPresentMap_10_000(Map_10_000 map) { Integer x = map.map.get(map.isPresent); return x == null ? -1 : x; } @Fork(1) @Benchmark public int mightBePresentMap_10_000_000(Map_10_000_000 map) { Integer x = map.map.get(map.mightBePresent); return x == null ? -1 : x; } @Fork(1) @Benchmark public int isPresentMap_10_000_000(Map_10_000_000 map) { Integer x = map.map.get(map.isPresent); return x == null ? -1 : x; } private static double[] generateTwoPoints(double upperBound, double lowerBound, int precision) { double x = ThreadLocalRandom.current().nextDouble(lowerBound, upperBound); x = BigDecimal.valueOf(x).setScale(precision, RoundingMode.HALF_UP).doubleValue(); double y = ThreadLocalRandom.current().nextDouble(lowerBound, upperBound); y = BigDecimal.valueOf(x).setScale(precision, RoundingMode.HALF_UP).doubleValue(); return new double[] { x, y }; } }
And the actual results:
Benchmark (howManyEntries) Mode Cnt Score Error Units hashmap8Millions.EightMillionsTest.isPresent 1 avgt 5 8.787 ± 0.259 ns/op hashmap8Millions.EightMillionsTest.isPresent 10 avgt 5 9.988 ± 0.283 ns/op hashmap8Millions.EightMillionsTest.isPresent 256 avgt 5 9.146 ± 2.081 ns/op hashmap8Millions.EightMillionsTest.isPresent 10000 avgt 5 8.871 ± 0.574 ns/op hashmap8Millions.EightMillionsTest.isPresent 1000000 avgt 5 8.894 ± 0.676 ns/op hashmap8Millions.EightMillionsTest.isPresent 10000000 avgt 5 10.884 ± 5.623 ns/op hashmap8Millions.EightMillionsTest.mightBePresent 1 avgt 5 4.607 ± 0.175 ns/op hashmap8Millions.EightMillionsTest.mightBePresent 10 avgt 5 4.713 ± 0.944 ns/op hashmap8Millions.EightMillionsTest.mightBePresent 256 avgt 5 5.283 ± 0.511 ns/op hashmap8Millions.EightMillionsTest.mightBePresent 10000 avgt 5 8.944 ± 0.144 ns/op hashmap8Millions.EightMillionsTest.mightBePresent 1000000 avgt 5 10.256 ± 0.121 ns/op hashmap8Millions.EightMillionsTest.mightBePresent 10000000 avgt 5 8.764 ± 0.504 ns/op
Note that this is nano-seconds , far from it ...
Eugene
source share