java - 一个java映射,其中键是已知的,但值应该稍后计算,因为它们很昂贵

标签 java caching

是否存在已知键的 java 映射实现,但仅应在第一次访问时计算值,因为计算值的成本很高。

下面演示了我希望它如何工作。

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可能会以只读方式返回。

map 本身可以通过传入 Set<String> 来创建。定义键和 Function<String, String>给定一个键返回它的值。

最佳答案

一个解决方案可能是拥有一个接受一组键的Set的Map和一个给定键可以计算值的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 - 一个java映射,其中键是已知的,但值应该稍后计算,因为它们很昂贵,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60217387/

相关文章:

JavaFX:没有 JavaFX 样式属性的可编辑 TableView

java - 数据类型为 `TIMESTAMP(6) with Local Time Zone` 的 oracle 11g 在 csv 中存档了 Windows 和 Linux 中的不同数据

java - 在 Java 对象被垃圾收集之前对其进行回调

asp.net - 应用程序池的Appfabric缓存和回收

python - 用于 Web 应用程序的 Django 缓存

java - Android:当 SearchView 的内容随 Google Places API 的结果更改时更新 ListView

java - Weblogic 12c - Tibco EMS - IllegalAccessError

http - 缓存破坏如何在 index.html 上工作?

javascript - 在 Mobile Safari 中将图像缓存到屏幕外

java - Hibernate 列表映射在一个单独的表中