首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java 8对供应商有缓存支持吗?

Java 8对供应商有缓存支持吗?
EN

Stack Overflow用户
提问于 2016-02-11 13:18:54
回答 3查看 17.8K关注 0票数 34

guava库有它自己的不扩展Java8 SupplierSupplier。此外,guava还为供应商提供了缓存- Suppliers#memoize

有没有类似的东西,但对Java8供应商来说?

EN

回答 3

Stack Overflow用户

发布于 2016-02-11 14:44:06

没有用于记忆化的内置Java函数,尽管实现它并不是很困难,例如,如下所示:

代码语言:javascript
复制
public static <T> Supplier<T> memoize(Supplier<T> delegate) {
    AtomicReference<T> value = new AtomicReference<>();
    return () -> {
        T val = value.get();
        if (val == null) {
            val = value.updateAndGet(cur -> cur == null ? 
                    Objects.requireNonNull(delegate.get()) : cur);
        }
        return val;
    };
}

请注意,存在不同的实现方法。如果被记录的供应者同时从不同的线程请求了几次,则上述实现可以多次调用委托。有时,这样的实现比使用锁的显式同步更可取。如果首选lock,则可以使用DCL:

代码语言:javascript
复制
public static <T> Supplier<T> memoizeLock(Supplier<T> delegate) {
    AtomicReference<T> value = new AtomicReference<>();
    return () -> {
        T val = value.get();
        if (val == null) {
            synchronized(value) {
                val = value.get();
                if (val == null) {
                    val = Objects.requireNonNull(delegate.get());
                    value.set(val);
                }
            }
        }
        return val;
    };
}

还请注意,正如@LouisWasserman在评论中正确提到的那样,您可以使用方法引用轻松地将JDK供应商转换为Guava供应商,反之亦然:

代码语言:javascript
复制
java.util.function.Supplier<String> jdkSupplier = () -> "test";
com.google.common.base.Supplier<String> guavaSupplier = jdkSupplier::get;
java.util.function.Supplier<String> jdkSupplierBack = guavaSupplier::get;

因此,在Guava和JDK函数之间切换并不是什么大问题。

票数 34
EN

Stack Overflow用户

发布于 2016-02-11 17:34:57

最简单的解决方案是

代码语言:javascript
复制
public static <T> Supplier<T> memoize(Supplier<T> original) {
    ConcurrentHashMap<Object, T> store=new ConcurrentHashMap<>();
    return ()->store.computeIfAbsent("dummy", key->original.get());
}

然而,最简单的并不总是最有效的。

如果你想要一个干净有效的解决方案,求助于匿名内部类来保存可变状态将是值得的:

代码语言:javascript
复制
public static <T> Supplier<T> memoize1(Supplier<T> original) {
    return new Supplier<T>() {
        Supplier<T> delegate = this::firstTime;
        boolean initialized;
        public T get() {
            return delegate.get();
        }
        private synchronized T firstTime() {
            if(!initialized) {
                T value=original.get();
                delegate=() -> value;
                initialized=true;
            }
            return delegate.get();
        }
    };
}

这使用了一个委托的供应商,它将执行第一次操作,然后用一个无条件返回第一次评估结果的供应商替换它自己。由于它具有final字段语义,因此可以在不进行任何额外同步的情况下无条件地返回它。

synchronized方法firstTime()中,仍然需要一个initialized标志,因为在初始化期间发生并发访问的情况下,多个线程可能会在委托被替换之前在方法的入口处等待。因此,这些线程需要检测初始化是否已经完成。所有后续访问都将读取新的委托供应商,并快速获取值。

票数 27
EN

Stack Overflow用户

发布于 2020-04-13 13:14:42

Java 8上Guava 20的一个简单包装器:

代码语言:javascript
复制
static <T> java.util.function.Supplier<T> memoize(java.util.function.Supplier<? extends T> supplier) {
    return com.google.common.base.Suppliers.memoize(supplier::get)::get;
}
票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35331327

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档