LongLongHashMap.get should no longer throw NoSuchElementException
In many use cases it is more efficient to have a getter that returns a default value instead of throwing an exception. The exception forces every consumer to call containsKey() before calling get(). In cases where the consumer wants to use a default value this is unnecessary.
This commit is contained in:
@@ -1,10 +1,11 @@
|
|||||||
package org.lucares.collections;
|
package org.lucares.collections;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.NoSuchElementException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A hash map where key and value are primitive longs.
|
* A hash map where key and value are primitive longs.
|
||||||
|
*
|
||||||
|
* @see LongObjHashMap
|
||||||
*/
|
*/
|
||||||
public class LongLongHashMap {
|
public class LongLongHashMap {
|
||||||
|
|
||||||
@@ -125,21 +126,19 @@ public class LongLongHashMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the value for the given key if it exists. This method throws a
|
* Returns the value for the given key if it exists or {@code defaultValue} if it does not exist.
|
||||||
* {@link NoSuchElementException} if the key does not exist. Use
|
|
||||||
* {@link #containsKey(long)} to check before calling {@link #get(long)}.
|
|
||||||
*
|
*
|
||||||
* @param key the key
|
* @param key the key
|
||||||
* @return the value if it exists
|
* @param defaultValue the value to return if the given key does not exist
|
||||||
* @throws NoSuchElementException if the value does not exist
|
* @return the value if it exists, or defaultValue
|
||||||
*/
|
*/
|
||||||
public long get(final long key) {
|
public long get(final long key, long defaultValue) {
|
||||||
|
|
||||||
if (key == NULL_KEY) {
|
if (key == NULL_KEY) {
|
||||||
if (zeroValue != null) {
|
if (zeroValue != null) {
|
||||||
return zeroValue;
|
return zeroValue;
|
||||||
}
|
}
|
||||||
throw new NoSuchElementException();
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
final int searchStart = spread(key);
|
final int searchStart = spread(key);
|
||||||
@@ -150,7 +149,7 @@ public class LongLongHashMap {
|
|||||||
}
|
}
|
||||||
currentPosition = (currentPosition + 1) % keys.length;
|
currentPosition = (currentPosition + 1) % keys.length;
|
||||||
} while (currentPosition != searchStart);
|
} while (currentPosition != searchStart);
|
||||||
throw new NoSuchElementException();
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -206,7 +205,7 @@ public class LongLongHashMap {
|
|||||||
* <p>
|
* <p>
|
||||||
* The mapping for given key is updated by calling {@code function} with the old
|
* The mapping for given key is updated by calling {@code function} with the old
|
||||||
* value. The return value will be set as new value. If the map does not contain
|
* value. The return value will be set as new value. If the map does not contain
|
||||||
* a mapping for the key, then {@code function} is with
|
* a mapping for the key, then {@code function} is called with
|
||||||
* {@code initialValueIfAbsent}.
|
* {@code initialValueIfAbsent}.
|
||||||
*
|
*
|
||||||
* @param key the key
|
* @param key the key
|
||||||
@@ -280,7 +279,7 @@ public class LongLongHashMap {
|
|||||||
for (int i = 0; i < sortedKeys.length; i++) {
|
for (int i = 0; i < sortedKeys.length; i++) {
|
||||||
final long key = sortedKeys[i];
|
final long key = sortedKeys[i];
|
||||||
if (key != EMPTY_SLOT) {
|
if (key != EMPTY_SLOT) {
|
||||||
consumer.accept(key, get(key));
|
consumer.accept(key, get(key, 0)); // the default value of 'get' will not be used, because the key exists
|
||||||
} else if (key == EMPTY_SLOT) {
|
} else if (key == EMPTY_SLOT) {
|
||||||
final int posFirstKey = findPosOfFirstPositiveKey(sortedKeys);
|
final int posFirstKey = findPosOfFirstPositiveKey(sortedKeys);
|
||||||
if (posFirstKey < 0) {
|
if (posFirstKey < 0) {
|
||||||
|
|||||||
@@ -30,12 +30,12 @@ public class LongLongHashMapTest {
|
|||||||
// add value and check it is in the map
|
// add value and check it is in the map
|
||||||
map.put(key, valueA);
|
map.put(key, valueA);
|
||||||
Assertions.assertTrue(map.containsKey(key));
|
Assertions.assertTrue(map.containsKey(key));
|
||||||
Assertions.assertEquals(valueA, map.get(key));
|
Assertions.assertEquals(valueA, map.get(key, Long.MIN_VALUE));
|
||||||
Assertions.assertEquals(1, map.size());
|
Assertions.assertEquals(1, map.size());
|
||||||
|
|
||||||
// overwrite value
|
// overwrite value
|
||||||
map.put(key, valueB);
|
map.put(key, valueB);
|
||||||
Assertions.assertEquals(valueB, map.get(key));
|
Assertions.assertEquals(valueB, map.get(key, Long.MIN_VALUE));
|
||||||
Assertions.assertEquals(1, map.size());
|
Assertions.assertEquals(1, map.size());
|
||||||
|
|
||||||
// remove value and check it is gone
|
// remove value and check it is gone
|
||||||
@@ -50,10 +50,10 @@ public class LongLongHashMapTest {
|
|||||||
|
|
||||||
final long key = 1;
|
final long key = 1;
|
||||||
map.compute(key, 6, l -> l + 1);
|
map.compute(key, 6, l -> l + 1);
|
||||||
Assertions.assertEquals(7, map.get(key), "initialValueIfAbsent is used when there is no mapping for the key");
|
Assertions.assertEquals(7, map.get(key, Long.MIN_VALUE), "initialValueIfAbsent is used when there is no mapping for the key");
|
||||||
|
|
||||||
map.compute(key, 6, l -> l + 1);
|
map.compute(key, 6, l -> l + 1);
|
||||||
Assertions.assertEquals(8, map.get(key), "update function is called when 'zeroKey' is set");
|
Assertions.assertEquals(8, map.get(key, Long.MIN_VALUE), "update function is called when 'zeroKey' is set");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -61,10 +61,10 @@ public class LongLongHashMapTest {
|
|||||||
final LongLongHashMap map = new LongLongHashMap();
|
final LongLongHashMap map = new LongLongHashMap();
|
||||||
final long key = 1;
|
final long key = 1;
|
||||||
map.compute(key, 6, l -> l + 1);
|
map.compute(key, 6, l -> l + 1);
|
||||||
Assertions.assertEquals(7, map.get(key), "initialValueIfAbsent is used when there is no mapping for the key");
|
Assertions.assertEquals(7, map.get(key, Long.MIN_VALUE), "initialValueIfAbsent is used when there is no mapping for the key");
|
||||||
|
|
||||||
map.compute(key, 6, l -> l + 1);
|
map.compute(key, 6, l -> l + 1);
|
||||||
Assertions.assertEquals(8, map.get(key), "update function is called when key is set");
|
Assertions.assertEquals(8, map.get(key, Long.MIN_VALUE), "update function is called when key is set");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -79,7 +79,7 @@ public class LongLongHashMapTest {
|
|||||||
map.put(l, l);
|
map.put(l, l);
|
||||||
});
|
});
|
||||||
entries.stream().forEachOrdered(l -> {
|
entries.stream().forEachOrdered(l -> {
|
||||||
Assertions.assertEquals(l, map.get(l));
|
Assertions.assertEquals(l, map.get(l, Long.MIN_VALUE));
|
||||||
});
|
});
|
||||||
Assertions.assertEquals(16, map.getCapacity(), "capacity after adding 12 entries must be a the smallest number "
|
Assertions.assertEquals(16, map.getCapacity(), "capacity after adding 12 entries must be a the smallest number "
|
||||||
+ "that satisfies initialCapacity * 2^n >= entries/fillFactor");
|
+ "that satisfies initialCapacity * 2^n >= entries/fillFactor");
|
||||||
@@ -95,7 +95,7 @@ public class LongLongHashMapTest {
|
|||||||
|
|
||||||
keysWithSameSpread.stream().forEach(l -> map.put(l, l));
|
keysWithSameSpread.stream().forEach(l -> map.put(l, l));
|
||||||
Assertions.assertEquals(keysWithSameSpread.size(), map.size());
|
Assertions.assertEquals(keysWithSameSpread.size(), map.size());
|
||||||
keysWithSameSpread.stream().forEach(l -> Assertions.assertEquals(l, map.get(l)));
|
keysWithSameSpread.stream().forEach(l -> Assertions.assertEquals(l, map.get(l, Long.MIN_VALUE)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user