8176894: Provide specialized implementation for default methods putIfAbsent, computeIfAbsent, computeIfPresent, compute, merge in TreeMap
Co-authored-by: Sergey Kuksenko <sergey.kuksenko@oracle.com> Reviewed-by: martin, stuefe, rriggs
This commit is contained in:
parent
3790e58090
commit
0386b7d0c3
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -29,6 +29,7 @@ import java.io.Serializable;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* A Red-Black tree based {@link NavigableMap} implementation.
|
||||
@ -341,8 +342,7 @@ public class TreeMap<K,V>
|
||||
// Offload comparator-based version for sake of performance
|
||||
if (comparator != null)
|
||||
return getEntryUsingComparator(key);
|
||||
if (key == null)
|
||||
throw new NullPointerException();
|
||||
Objects.requireNonNull(key);
|
||||
@SuppressWarnings("unchecked")
|
||||
Comparable<? super K> k = (Comparable<? super K>) key;
|
||||
Entry<K,V> p = root;
|
||||
@ -531,14 +531,37 @@ public class TreeMap<K,V>
|
||||
* does not permit null keys
|
||||
*/
|
||||
public V put(K key, V value) {
|
||||
return put(key, value, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public V putIfAbsent(K key, V value) {
|
||||
return put(key, value, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>This method will, on a best-effort basis, throw a
|
||||
* {@link ConcurrentModificationException} if it is detected that the
|
||||
* mapping function modifies this map during computation.
|
||||
*
|
||||
* @throws ConcurrentModificationException if it is detected that the
|
||||
* mapping function modified this map
|
||||
*/
|
||||
@Override
|
||||
public V computeIfAbsent(K key, Function<? super K, ? extends V> mappingFunction) {
|
||||
Objects.requireNonNull(mappingFunction);
|
||||
V newValue;
|
||||
Entry<K,V> t = root;
|
||||
if (t == null) {
|
||||
compare(key, key); // type (and possibly null) check
|
||||
|
||||
root = new Entry<>(key, value, null);
|
||||
size = 1;
|
||||
modCount++;
|
||||
return null;
|
||||
newValue = callMappingFunctionWithCheck(key, mappingFunction);
|
||||
if (newValue != null) {
|
||||
addEntryToEmptyMap(key, newValue);
|
||||
return newValue;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
int cmp;
|
||||
Entry<K,V> parent;
|
||||
@ -553,14 +576,12 @@ public class TreeMap<K,V>
|
||||
else if (cmp > 0)
|
||||
t = t.right;
|
||||
else
|
||||
return t.setValue(value);
|
||||
return t.value;
|
||||
} while (t != null);
|
||||
}
|
||||
else {
|
||||
if (key == null)
|
||||
throw new NullPointerException();
|
||||
} else {
|
||||
Objects.requireNonNull(key);
|
||||
@SuppressWarnings("unchecked")
|
||||
Comparable<? super K> k = (Comparable<? super K>) key;
|
||||
Comparable<? super K> k = (Comparable<? super K>) key;
|
||||
do {
|
||||
parent = t;
|
||||
cmp = k.compareTo(t.key);
|
||||
@ -569,20 +590,271 @@ public class TreeMap<K,V>
|
||||
else if (cmp > 0)
|
||||
t = t.right;
|
||||
else
|
||||
return t.setValue(value);
|
||||
return t.value;
|
||||
} while (t != null);
|
||||
}
|
||||
newValue = callMappingFunctionWithCheck(key, mappingFunction);
|
||||
if (newValue != null) {
|
||||
addEntry(key, newValue, parent, cmp < 0);
|
||||
return newValue;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>This method will, on a best-effort basis, throw a
|
||||
* {@link ConcurrentModificationException} if it is detected that the
|
||||
* remapping function modifies this map during computation.
|
||||
*
|
||||
* @throws ConcurrentModificationException if it is detected that the
|
||||
* remapping function modified this map
|
||||
*/
|
||||
@Override
|
||||
public V computeIfPresent(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
|
||||
Objects.requireNonNull(remappingFunction);
|
||||
Entry<K,V> oldEntry = getEntry(key);
|
||||
if (oldEntry != null && oldEntry.value != null) {
|
||||
return remapValue(oldEntry, key, remappingFunction);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>This method will, on a best-effort basis, throw a
|
||||
* {@link ConcurrentModificationException} if it is detected that the
|
||||
* remapping function modifies this map during computation.
|
||||
*
|
||||
* @throws ConcurrentModificationException if it is detected that the
|
||||
* remapping function modified this map
|
||||
*/
|
||||
@Override
|
||||
public V compute(K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
|
||||
Objects.requireNonNull(remappingFunction);
|
||||
V newValue;
|
||||
Entry<K,V> t = root;
|
||||
if (t == null) {
|
||||
newValue = callRemappingFunctionWithCheck(key, null, remappingFunction);
|
||||
if (newValue != null) {
|
||||
addEntryToEmptyMap(key, newValue);
|
||||
return newValue;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
int cmp;
|
||||
Entry<K,V> parent;
|
||||
// split comparator and comparable paths
|
||||
Comparator<? super K> cpr = comparator;
|
||||
if (cpr != null) {
|
||||
do {
|
||||
parent = t;
|
||||
cmp = cpr.compare(key, t.key);
|
||||
if (cmp < 0)
|
||||
t = t.left;
|
||||
else if (cmp > 0)
|
||||
t = t.right;
|
||||
else
|
||||
return remapValue(t, key, remappingFunction);
|
||||
} while (t != null);
|
||||
} else {
|
||||
Objects.requireNonNull(key);
|
||||
@SuppressWarnings("unchecked")
|
||||
Comparable<? super K> k = (Comparable<? super K>) key;
|
||||
do {
|
||||
parent = t;
|
||||
cmp = k.compareTo(t.key);
|
||||
if (cmp < 0)
|
||||
t = t.left;
|
||||
else if (cmp > 0)
|
||||
t = t.right;
|
||||
else
|
||||
return remapValue(t, key, remappingFunction);
|
||||
} while (t != null);
|
||||
}
|
||||
newValue = callRemappingFunctionWithCheck(key, null, remappingFunction);
|
||||
if (newValue != null) {
|
||||
addEntry(key, newValue, parent, cmp < 0);
|
||||
return newValue;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* <p>This method will, on a best-effort basis, throw a
|
||||
* {@link ConcurrentModificationException} if it is detected that the
|
||||
* remapping function modifies this map during computation.
|
||||
*
|
||||
* @throws ConcurrentModificationException if it is detected that the
|
||||
* remapping function modified this map
|
||||
*/
|
||||
@Override
|
||||
public V merge(K key, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
|
||||
Objects.requireNonNull(remappingFunction);
|
||||
Objects.requireNonNull(value);
|
||||
Entry<K,V> t = root;
|
||||
if (t == null) {
|
||||
addEntryToEmptyMap(key, value);
|
||||
return value;
|
||||
}
|
||||
int cmp;
|
||||
Entry<K,V> parent;
|
||||
// split comparator and comparable paths
|
||||
Comparator<? super K> cpr = comparator;
|
||||
if (cpr != null) {
|
||||
do {
|
||||
parent = t;
|
||||
cmp = cpr.compare(key, t.key);
|
||||
if (cmp < 0)
|
||||
t = t.left;
|
||||
else if (cmp > 0)
|
||||
t = t.right;
|
||||
else return mergeValue(t, value, remappingFunction);
|
||||
} while (t != null);
|
||||
} else {
|
||||
Objects.requireNonNull(key);
|
||||
@SuppressWarnings("unchecked")
|
||||
Comparable<? super K> k = (Comparable<? super K>) key;
|
||||
do {
|
||||
parent = t;
|
||||
cmp = k.compareTo(t.key);
|
||||
if (cmp < 0)
|
||||
t = t.left;
|
||||
else if (cmp > 0)
|
||||
t = t.right;
|
||||
else return mergeValue(t, value, remappingFunction);
|
||||
} while (t != null);
|
||||
}
|
||||
addEntry(key, value, parent, cmp < 0);
|
||||
return value;
|
||||
}
|
||||
|
||||
private V callMappingFunctionWithCheck(K key, Function<? super K, ? extends V> mappingFunction) {
|
||||
int mc = modCount;
|
||||
V newValue = mappingFunction.apply(key);
|
||||
if (mc != modCount) {
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
return newValue;
|
||||
}
|
||||
|
||||
private V callRemappingFunctionWithCheck(K key, V oldValue, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
|
||||
int mc = modCount;
|
||||
V newValue = remappingFunction.apply(key, oldValue);
|
||||
if (mc != modCount) {
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
return newValue;
|
||||
}
|
||||
|
||||
private void addEntry(K key, V value, Entry<K, V> parent, boolean addToLeft) {
|
||||
Entry<K,V> e = new Entry<>(key, value, parent);
|
||||
if (cmp < 0)
|
||||
if (addToLeft)
|
||||
parent.left = e;
|
||||
else
|
||||
parent.right = e;
|
||||
fixAfterInsertion(e);
|
||||
size++;
|
||||
modCount++;
|
||||
}
|
||||
|
||||
private void addEntryToEmptyMap(K key, V value) {
|
||||
compare(key, key); // type (and possibly null) check
|
||||
root = new Entry<>(key, value, null);
|
||||
size = 1;
|
||||
modCount++;
|
||||
}
|
||||
|
||||
private V put(K key, V value, boolean replaceOld) {
|
||||
Entry<K,V> t = root;
|
||||
if (t == null) {
|
||||
addEntryToEmptyMap(key, value);
|
||||
return null;
|
||||
}
|
||||
int cmp;
|
||||
Entry<K,V> parent;
|
||||
// split comparator and comparable paths
|
||||
Comparator<? super K> cpr = comparator;
|
||||
if (cpr != null) {
|
||||
do {
|
||||
parent = t;
|
||||
cmp = cpr.compare(key, t.key);
|
||||
if (cmp < 0)
|
||||
t = t.left;
|
||||
else if (cmp > 0)
|
||||
t = t.right;
|
||||
else {
|
||||
V oldValue = t.value;
|
||||
if (replaceOld || oldValue == null) {
|
||||
t.value = value;
|
||||
}
|
||||
return oldValue;
|
||||
}
|
||||
} while (t != null);
|
||||
} else {
|
||||
Objects.requireNonNull(key);
|
||||
@SuppressWarnings("unchecked")
|
||||
Comparable<? super K> k = (Comparable<? super K>) key;
|
||||
do {
|
||||
parent = t;
|
||||
cmp = k.compareTo(t.key);
|
||||
if (cmp < 0)
|
||||
t = t.left;
|
||||
else if (cmp > 0)
|
||||
t = t.right;
|
||||
else {
|
||||
V oldValue = t.value;
|
||||
if (replaceOld || oldValue == null) {
|
||||
t.value = value;
|
||||
}
|
||||
return oldValue;
|
||||
}
|
||||
} while (t != null);
|
||||
}
|
||||
addEntry(key, value, parent, cmp < 0);
|
||||
return null;
|
||||
}
|
||||
|
||||
private V remapValue(Entry<K,V> t, K key, BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
|
||||
V newValue = callRemappingFunctionWithCheck(key, t.value, remappingFunction);
|
||||
if (newValue == null) {
|
||||
deleteEntry(t);
|
||||
return null;
|
||||
} else {
|
||||
// replace old mapping
|
||||
t.value = newValue;
|
||||
return newValue;
|
||||
}
|
||||
}
|
||||
|
||||
private V mergeValue(Entry<K,V> t, V value, BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
|
||||
V oldValue = t.value;
|
||||
V newValue;
|
||||
if (t.value == null) {
|
||||
newValue = value;
|
||||
} else {
|
||||
int mc = modCount;
|
||||
newValue = remappingFunction.apply(oldValue, value);
|
||||
if (mc != modCount) {
|
||||
throw new ConcurrentModificationException();
|
||||
}
|
||||
}
|
||||
if (newValue == null) {
|
||||
deleteEntry(t);
|
||||
return null;
|
||||
} else {
|
||||
// replace old mapping
|
||||
t.value = newValue;
|
||||
return newValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the mapping for this key from this TreeMap if present.
|
||||
*
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -30,6 +30,7 @@ import java.util.Hashtable;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
@ -53,6 +54,7 @@ public class FunctionalCMEs {
|
||||
new Object[]{new HashMap<>(), true},
|
||||
new Object[]{new Hashtable<>(), true},
|
||||
new Object[]{new LinkedHashMap<>(), true},
|
||||
new Object[]{new TreeMap<>(), true},
|
||||
// Test default Map methods - no CME
|
||||
new Object[]{new Defaults.ExtendsAbstractMap<>(), false}
|
||||
).iterator();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -27,11 +27,19 @@
|
||||
* @run testng/othervm -Dtest.map.collisions.shortrun=true InPlaceOpsCollisions
|
||||
* @summary Ensure overrides of in-place operations in Maps behave well with lots of collisions.
|
||||
*/
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.testng.annotations.DataProvider;
|
||||
import org.testng.annotations.Test;
|
||||
import static org.testng.Assert.assertTrue;
|
||||
import static org.testng.Assert.assertFalse;
|
||||
@ -71,6 +79,19 @@ public class InPlaceOpsCollisions extends MapWithCollisionsProviders {
|
||||
String.format("map expected size m%d != k%d", map.size(), keys.length));
|
||||
}
|
||||
|
||||
@Test(dataProvider = "nullValueFriendlyMaps")
|
||||
void testPutIfAbsentOverwriteNull(String desc, Supplier<Map<Object, Object>> ms) {
|
||||
Map<Object, Object> map = ms.get();
|
||||
map.put("key", null);
|
||||
assertEquals(map.size(), 1, desc + ": size != 1");
|
||||
assertTrue(map.containsKey("key"), desc + ": does not have key");
|
||||
assertNull(map.get("key"), desc + ": value is not null");
|
||||
map.putIfAbsent("key", "value"); // must rewrite
|
||||
assertEquals(map.size(), 1, desc + ": size != 1");
|
||||
assertTrue(map.containsKey("key"), desc + ": does not have key");
|
||||
assertEquals(map.get("key"), "value", desc + ": value is not 'value'");
|
||||
}
|
||||
|
||||
@Test(dataProvider = "mapsWithObjectsAndStrings")
|
||||
void testRemoveMapping(String desc, Supplier<Map<Object, Object>> ms, Object val) {
|
||||
Map<Object, Object> map = ms.get();
|
||||
@ -496,4 +517,13 @@ public class InPlaceOpsCollisions extends MapWithCollisionsProviders {
|
||||
}
|
||||
}
|
||||
|
||||
@DataProvider
|
||||
public Iterator<Object[]> nullValueFriendlyMaps() {
|
||||
return Arrays.asList(
|
||||
new Object[]{"HashMap", (Supplier<Map<?, ?>>) HashMap::new},
|
||||
new Object[]{"LinkedHashMap", (Supplier<Map<?, ?>>) LinkedHashMap::new},
|
||||
new Object[]{"TreeMap", (Supplier<Map<?, ?>>) TreeMap::new},
|
||||
new Object[]{"TreeMap(cmp)", (Supplier<Map<?, ?>>) () -> new TreeMap<>(Comparator.reverseOrder())}
|
||||
).iterator();
|
||||
}
|
||||
}
|
||||
|
151
test/micro/org/openjdk/bench/java/util/TreeMapUpdate.java
Normal file
151
test/micro/org/openjdk/bench/java/util/TreeMapUpdate.java
Normal file
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package org.openjdk.bench.java.util;
|
||||
|
||||
import org.openjdk.jmh.annotations.Benchmark;
|
||||
import org.openjdk.jmh.annotations.BenchmarkMode;
|
||||
import org.openjdk.jmh.annotations.Fork;
|
||||
import org.openjdk.jmh.annotations.Measurement;
|
||||
import org.openjdk.jmh.annotations.Mode;
|
||||
import org.openjdk.jmh.annotations.OutputTimeUnit;
|
||||
import org.openjdk.jmh.annotations.Param;
|
||||
import org.openjdk.jmh.annotations.Scope;
|
||||
import org.openjdk.jmh.annotations.Setup;
|
||||
import org.openjdk.jmh.annotations.State;
|
||||
import org.openjdk.jmh.annotations.Warmup;
|
||||
import org.openjdk.jmh.infra.Blackhole;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
@BenchmarkMode(Mode.AverageTime)
|
||||
@OutputTimeUnit(TimeUnit.NANOSECONDS)
|
||||
@Warmup(iterations = 5, time = 500, timeUnit = TimeUnit.MILLISECONDS)
|
||||
@Measurement(iterations = 10, time = 500, timeUnit = TimeUnit.MILLISECONDS)
|
||||
@Fork(3)
|
||||
@State(Scope.Thread)
|
||||
public class TreeMapUpdate {
|
||||
@Param({"10", "1000", "100000"})
|
||||
public int size;
|
||||
|
||||
@Param({"true", "false"})
|
||||
public boolean comparator;
|
||||
|
||||
@Param({"true", "false"})
|
||||
public boolean preFill;
|
||||
|
||||
@Param({"0"})
|
||||
public long seed;
|
||||
|
||||
private Supplier<TreeMap<Integer, Integer>> supplier;
|
||||
|
||||
private Integer[] keys;
|
||||
|
||||
@Setup
|
||||
public void setUp() {
|
||||
supplier = comparator ? () -> new TreeMap<>(Comparator.reverseOrder()) : TreeMap::new;
|
||||
keys = IntStream.range(0, size).boxed().toArray(Integer[]::new);
|
||||
Random rnd = seed == 0 ? new Random() : new Random(seed);
|
||||
Collections.shuffle(Arrays.asList(keys, rnd));
|
||||
if (preFill) {
|
||||
TreeMap<Integer, Integer> template = Arrays.stream(keys)
|
||||
.collect(Collectors.toMap(Function.identity(), Function.identity(), (a, b) -> a, supplier));
|
||||
supplier = () -> new TreeMap<>(template);
|
||||
}
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public Map<Integer, Integer> baseline() {
|
||||
// Just create map (empty or pre-filled)
|
||||
return supplier.get();
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public Map<Integer, Integer> put(Blackhole bh) {
|
||||
Map<Integer, Integer> map = supplier.get();
|
||||
Integer[] keys = this.keys;
|
||||
for (Integer key : keys) {
|
||||
bh.consume(map.put(key, key));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public Map<Integer, Integer> putIfAbsent(Blackhole bh) {
|
||||
Map<Integer, Integer> map = supplier.get();
|
||||
Integer[] keys = this.keys;
|
||||
for (Integer key : keys) {
|
||||
bh.consume(map.putIfAbsent(key, key));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public Map<Integer, Integer> computeIfAbsent(Blackhole bh) {
|
||||
Map<Integer, Integer> map = supplier.get();
|
||||
Integer[] keys = this.keys;
|
||||
for (Integer key : keys) {
|
||||
bh.consume(map.computeIfAbsent(key, k -> k));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public Map<Integer, Integer> compute(Blackhole bh) {
|
||||
Map<Integer, Integer> map = supplier.get();
|
||||
Integer[] keys = this.keys;
|
||||
for (Integer key : keys) {
|
||||
bh.consume(map.compute(key, (k, old) -> k));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public Map<Integer, Integer> computeIfPresent(Blackhole bh) {
|
||||
Map<Integer, Integer> map = supplier.get();
|
||||
Integer[] keys = this.keys;
|
||||
for (Integer key : keys) {
|
||||
bh.consume(map.computeIfPresent(key, (k, old) -> k));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@Benchmark
|
||||
public Map<Integer, Integer> merge(Blackhole bh) {
|
||||
Map<Integer, Integer> map = supplier.get();
|
||||
Integer[] keys = this.keys;
|
||||
for (Integer key : keys) {
|
||||
bh.consume(map.merge(key, key, (k1, k2) -> k1));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user