perf: 优化 MapModifier 实现

This commit is contained in:
2026-05-21 22:14:22 +08:00
parent f7518063f8
commit 84112fcf45
2 changed files with 80 additions and 59 deletions

View File

@@ -18,16 +18,21 @@ package xyz.zhouxy.plusone.commons.collection;
import static xyz.zhouxy.plusone.commons.util.AssertTools.checkArgumentNotNull;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import com.google.common.annotations.Beta;
@@ -74,16 +79,17 @@ import com.google.common.annotations.Beta;
@Beta
public class MapModifier<K, V> {
@Nonnull
private Consumer<Map<K, V>> operators;
private final List<Consumer<Map<K, V>>> operations;
/**
* 创建一个空的 MapModifier
*/
public MapModifier() {
this.operators = m -> {
// do nothing
};
this.operations = new ArrayList<>();
}
public MapModifier(int initialCapacity) {
this.operations = new ArrayList<>(initialCapacity);
}
/**
@@ -132,27 +138,6 @@ public class MapModifier<K, V> {
return addOperationInternal(map -> map.putAll(otherMap));
}
/**
* 添加多个键值对。
*
* <p>
* <b>注意:键值对是否允许为 {@code null},由最终作用的 {@link Map} 类型决定。</b>
*
* @param entries 要添加的键值对集合
* @return MapModifier
*/
@SafeVarargs
public final MapModifier<K, V> putAll(Map.Entry<? extends K, ? extends V>... entries) {
if (entries.length == 0) {
return this;
}
return addOperationInternal(map -> {
for (Map.Entry<? extends K, ? extends V> entry : entries) {
map.put(entry.getKey(), entry.getValue());
}
});
}
/**
* 当 {@code key} 不存在时,计算对应的值,并添加到 {@code map} 中。
*
@@ -168,6 +153,7 @@ public class MapModifier<K, V> {
*/
public MapModifier<K, V> computeIfAbsent(K key,
Function<? super K, ? extends V> mappingFunction) {
checkArgumentNotNull(mappingFunction, "Mapping function cannot be null.");
return addOperationInternal(map -> map.computeIfAbsent(key, mappingFunction));
}
@@ -186,6 +172,7 @@ public class MapModifier<K, V> {
*/
public MapModifier<K, V> computeIfPresent(K key,
BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
checkArgumentNotNull(remappingFunction, "Remapping function cannot be null.");
return addOperationInternal(map -> map.computeIfPresent(key, remappingFunction));
}
@@ -217,9 +204,10 @@ public class MapModifier<K, V> {
* @param map 要修改的 {@code map}
*/
public <T extends Map<K, V>> void modify(@Nullable T map) {
if (map != null) {
this.operators.accept(map);
if (map == null || this.operations.isEmpty()) {
return;
}
this.operations.forEach(operator -> operator.accept(map));
}
/**
@@ -237,17 +225,76 @@ public class MapModifier<K, V> {
return map;
}
/**
* 获取 {@code HashMap}
*
* @return {@code HashMap}
*/
public Map<K, V> getHashMap() {
return getAndModify(HashMap::new);
}
/**
* 获取 {@code LinkedHashMap}
*
* @return {@code LinkedHashMap}
*/
public Map<K, V> getLinkedHashMap() {
return getAndModify(LinkedHashMap::new);
}
/**
* 获取 {@code TreeMap}
*
* @return {@code TreeMap}
*/
public Map<K, V> getTreeMap() {
return getAndModify(TreeMap::new);
}
/**
* 获取 {@code ConcurrentHashMap}
*
* @return {@code ConcurrentHashMap}
*/
public Map<K, V> getConcurrentHashMap() {
return getAndModify(ConcurrentHashMap::new);
}
/**
* 创建一个有初始化数据的不可变的 {@code Map}
*
* @return 不可变的 {@code Map}
*/
public Map<K, V> getUnmodifiableMap() {
return Collections.unmodifiableMap(getAndModify(HashMap::new));
return Collections.unmodifiableMap(Objects.requireNonNull(getAndModify(HashMap::new)));
}
private MapModifier<K, V> addOperationInternal(Consumer<Map<K, V>> operator) {
this.operators = this.operators.andThen(operator);
this.operations.add(operator);
return this;
}
/**
* 获取操作数量
*
* @return 操作数量
*/
public int getOperatorCount() {
return this.operations.size();
}
/**
* 是否有操作
*
* @return 如果有操作,则返回 {@code true},否则返回 {@code false}
*/
public boolean hasOperations() {
return !this.operations.isEmpty();
}
@Override
public String toString() {
return "MapModifier [OperatorCount=" + this.operations.size() + "]";
}
}

View File

@@ -18,6 +18,7 @@ package xyz.zhouxy.plusone.commons.collection;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -206,34 +207,6 @@ public class MapModifierTests {
}, map);
}
@Test
void putAll_entries() {
Map<String, String> entries = new HashMap<String, String>() {
{
put("key1", "value1");
put("key2", "value2");
}
};
Map<String, String> map = new MapModifier<String, String>()
.putAll(new SimpleEntry<>("key1", "value1"),
new SimpleEntry<>("key2", "value2"))
.getAndModify(HashMap::new);
assertEquals(entries, map);
new MapModifier<String, String>()
.putAll()
.putAll(new SimpleEntry<>("key2", "newValue2"),
new SimpleEntry<>("key3", "value3"))
.modify(map);
assertEquals(new HashMap<String, String>() {
{
put("key1", "value1");
put("key2", "value2");
put("key2", "newValue2");
put("key3", "value3");
}
}, map);
}
@Test
void computeIfAbsent_keyAndFunction() {
Map<String, String> map = new MapModifier<String, String>()
@@ -254,6 +227,7 @@ public class MapModifierTests {
.computeIfAbsent("key1", k -> "newValue1")
.modify(map);
assertNotNull(map);
assertTrue(map.containsKey("key1"));
assertEquals("value1", map.get("key1"));
}