java - 一个 java 映射,其中键是已知的,但是值应该稍后计算,因为它们很昂贵
问题描述
是否存在已知键的 java map 实现,但是应该只在第一次访问时计算值,因为计算值很昂贵。
以下演示了我希望它如何工作。
someMap.keySet(); // Returns all keys but no values are computed.
someMap.get(key); // Returns the value for key computing it if needed.
这样做的原因是我有一些包含一堆数据的东西,并且这个对象返回数据,Map<String, String>
因为计算这些值的计算量很大,但是计算键很便宜。
Map 必须保持其类型,因此我不能返回Map<String, Supplier<String>>
. 返回的Map
可能以只读方式返回。
映射本身可以通过传入Set<String>
定义键和Function<String, String>
给定键返回其值的 a 来创建。
解决方案
一种解决方案可能是拥有一个 Map ,它带有一个Set
键,并且Function
给定一个键可以计算值。
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
/**
* Create a Map where we already know the keys but computing the values is expensive and so is delayed as
* much as possible.
*
*/
@AllArgsConstructor
public class MapWithValuesProvidedByFunction implements Map<String, String> {
/**
* All keys that are defined.
*/
private Set<String> keys;
/**
* A function which maps a key to its value.
*/
private Function<String, String> mappingFunction;
/**
* Holds all keys and values we have already computed.
*/
private final Map<String, String> computedValues = new HashMap<>();
@Override
public int size() {
return keys.size();
}
@Override
public boolean isEmpty() {
return keys.isEmpty();
}
@Override
public boolean containsKey(Object key) {
return keys.contains(key);
}
@Override
public boolean containsValue(Object value) {
if(computedValues.size() == keys.size()) return computedValues.containsValue(value);
for(String k : keys) {
String v = get(k);
if(v == value) return true;
if(v != null && v.equals(value)) return true;
}
return false;
}
@Override
public String get(Object key) {
if(keys.contains(key)) {
return computedValues.computeIfAbsent(key.toString(), mappingFunction);
}
return null;
}
@Override
public String put(String key, String value) {
throw new UnsupportedOperationException("Not modifiable");
}
@Override
public String remove(Object key) {
throw new UnsupportedOperationException("Not modifiable");
}
@Override
public void putAll(Map<? extends String, ? extends String> m) {
throw new UnsupportedOperationException("Not modifiable");
}
@Override
public void clear() {
throw new UnsupportedOperationException("Not modifiable");
}
@Override
public Set<String> keySet() {
return Collections.unmodifiableSet(keys);
}
@Override
public Collection<String> values() {
return keys.stream().map(this::get).collect(Collectors.toList());
}
@Override
public Set<java.util.Map.Entry<String, String>> entrySet() {
Set<Entry<String, String>> set = new HashSet<>();
for(String s : keys) {
set.add(new MyEntry(s, this::get));
}
return set;
}
@AllArgsConstructor
@EqualsAndHashCode
public class MyEntry implements Entry<String, String> {
private String key;
private Function<String, String> valueSupplier;
@Override
public String getKey() {
return key;
}
@Override
public String getValue() {
return valueSupplier.apply(key);
}
@Override
public String setValue(String value) {
throw new UnsupportedOperationException("Not modifiable");
}
}
}
正在使用的一个示例可能是:
Map<String, String> map = new MapWithValuesProvidedByFunction(
Set.of("a", "b", "c"), // The known keys
k -> "Slow to compute function"); // The function to make the values
将其更改为通用应该很容易。
我怀疑存在更好的解决方案,但这对其他人来说可能已经足够了。
推荐阅读
- java - For 循环 - 打印操作数除以二
- aggregate - EFK Stack 中的 Fluentbit 和 Fluentd,为什么我需要使用 fluentd?
- swift - 是否可以在 macOS 状态栏中放置矢量(或字体)图标?
- c# - .Net core中查询PK表时如何获取FK表数据?
- html - 如何以正确的方式对齐我的 flexbox 项目?
- cmyk - 如何使用 Magick.Net 将 RGB 位图数据保存为 CMYK tiff
- php - 将最小第二个偶数和最大第二个偶数相加:
- mysql - MYSQL 使用案例从 curdate() 中减去天数
- excel - VBA添加一个新工作表,如果名称存在添加一个数字
- javascript - 在 FormArray 中获取唯一值 - Angular