前言:📫 作者简介:小明java问道之路,专注于研究计算机底层,就职于金融公司后端高级工程师,擅长交易领域的高安全/可用/并发/性能的设计和架构📫
🏆 Java领域优质创作者、阿里云专家博主、华为云享专家🏆
🔥 如果此文还不错的话,还请👍关注、点赞、收藏三连支持👍一下博主哦
本文导读
Google开源Java工具库Guava+Apache Commons的核心类剖析
一、Guava包的核心类剖析
Guava工具包提供了一堆工具类,在实际的开发中能大大简化开发效率并且保证质量。
二、常用的工具类
Cache LRU缓存
public static void cacheTest() { Cache<Integer, String> cache = CacheBuilder.newBuilder().maximumSize(2).build(); cache.put(1, "first"); cache.put(2, "second"); cache.put(3, "third"); String cacheValue = cache.getIfPresent(1); System.out.println(cacheValue); // null System.out.println(cache.asMap()); // {3=third, 2=second} }
Cache<K,V> 是缓存的顶层接口,定义了 put (新增)、 getIfPresent (查询)、 invalidate (删除)等方法定义Cache 通过建造者模式来创建, CacheBuilder 自身有两种创建方式, newBuilder() 、 from(CacheBuilderSpec)等
package com.google.common.cache; import com.google.common.annotations.GwtCompatible; import com.google.common.collect.ImmutableMap; import com.google.common.util.concurrent.ExecutionError; import com.google.common.util.concurrent.UncheckedExecutionException; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ExecutionException; import javax.annotation.Nullable; /** * A semi-persistent mapping from keys to values. Cache entries are manually added using * {@link #get(Object, Callable)} or {@link #put(Object, Object)}, and are stored in the cache until * either evicted or manually invalidated. The common way to build instances is using * {@link CacheBuilder}. * * <p>Implementations of this interface are expected to be thread-safe, and can be safely accessed * by multiple concurrent threads. * * @author Charles Fry * @since 10.0 */ @GwtCompatible public interface Cache<K, V> { /** * Returns the value associated with {@code key} in this cache, or {@code null} if there is no * cached value for {@code key}. * * @since 11.0 */ @Nullable V getIfPresent(Object key); /** * Returns the value associated with {@code key} in this cache, obtaining that value from {@code * loader} if necessary. The method improves upon the conventional "if cached, return; otherwise * create, cache and return" pattern. For further improvements, use {@link LoadingCache} and its * {@link LoadingCache#get(Object) get(K)} method instead of this one. * * <p>Among the improvements that this method and {@code LoadingCache.get(K)} both provide are: * * <ul> * <li>{@linkplain LoadingCache#get(Object) awaiting the result of a pending load} rather than * starting a redundant one * <li>eliminating the error-prone caching boilerplate * <li>tracking load {@linkplain #stats statistics} * </ul> * * <p>Among the further improvements that {@code LoadingCache} can provide but this method cannot: * * <ul> * <li>consolidation of the loader logic to {@linkplain CacheBuilder#build(CacheLoader) a single * authoritative location} * <li>{@linkplain LoadingCache#refresh refreshing of entries}, including {@linkplain * CacheBuilder#refreshAfterWrite automated refreshing} * <li>{@linkplain LoadingCache#getAll bulk loading requests}, including {@linkplain * CacheLoader#loadAll bulk loading implementations} * </ul> * * <p><b>Warning:</b> For any given key, every {@code loader} used with it should compute the same * value. Otherwise, a call that passes one {@code loader} may return the result of another call * with a differently behaving {@code loader}. For example, a call that requests a short timeout * for an RPC may wait for a similar call that requests a long timeout, or a call by an * unprivileged user may return a resource accessible only to a privileged user making a similar * call. To prevent this problem, create a key object that includes all values that affect the * result of the query. Or use {@code LoadingCache.get(K)}, which lacks the ability to refer to * state other than that in the key. * * <p><b>Warning:</b> as with {@link CacheLoader#load}, {@code loader} <b>must not</b> return * {@code null}; it may either return a non-null value or throw an exception. * * <p>No observable state associated with this cache is modified until loading completes. * * @throws ExecutionException if a checked exception was thrown while loading the value * @throws UncheckedExecutionException if an unchecked exception was thrown while loading the * value * @throws ExecutionError if an error was thrown while loading the value * * @since 11.0 */ V get(K key, Callable<? extends V> loader) throws ExecutionException; /** * Returns a map of the values associated with {@code keys} in this cache. The returned map will * only contain entries which are already present in the cache. * * @since 11.0 */ ImmutableMap<K, V> getAllPresent(Iterable<?> keys); /** * Associates {@code value} with {@code key} in this cache. If the cache previously contained a * value associated with {@code key}, the old value is replaced by {@code value}. * * <p>Prefer {@link #get(Object, Callable)} when using the conventional "if cached, return; * otherwise create, cache and return" pattern. * * @since 11.0 */ void put(K key, V value); /** * Copies all of the mappings from the specified map to the cache. The effect of this call is * equivalent to that of calling {@code put(k, v)} on this map once for each mapping from key * {@code k} to value {@code v} in the specified map. The behavior of this operation is undefined * if the specified map is modified while the operation is in progress. * * @since 12.0 */ void putAll(Map<? extends K, ? extends V> m); /** * Discards any cached value for key {@code key}. */ void invalidate(Object key); /** * Discards any cached values for keys {@code keys}. * * @since 11.0 */ void invalidateAll(Iterable<?> keys); /** * Discards all entries in the cache. */ void invalidateAll(); /** * Returns the approximate number of entries in this cache. */ long size(); /** * Returns a current snapshot of this cache's cumulative statistics, or a set of default values if * the cache is not recording statistics. All statistics begin at zero and never decrease over the * lifetime of the cache. * * <p><b>Warning:</b> this cache may not be recording statistical data. For example, a cache * created using {@link CacheBuilder} only does so if the {@link CacheBuilder#recordStats} method * was called. If statistics are not being recorded, a {@code CacheStats} instance with zero for * all values is returned. * */ CacheStats stats(); /** * Returns a view of the entries stored in this cache as a thread-safe map. Modifications made to * the map directly affect the cache. * * <p>Iterators from the returned map are at least <i>weakly consistent</i>: they are safe for * concurrent use, but if the cache is modified (including by eviction) after the iterator is * created, it is undefined which of the changes (if any) will be reflected in that iterator. */ ConcurrentMap<K, V> asMap(); /** * Performs any pending maintenance operations needed by the cache. Exactly which activities are * performed -- if any -- is implementation-dependent. */ void cleanUp(); }
CacheBuilder为什么不可变
当对象被不可信的库调用时,不可变形式是安全的;不可变对象被多个线程调用时,不存在竞态条件问题;不可变集合不需要考虑变化,因此可以节省时间和空间。
所有不可变的集合都比它们的可变形式有更好的内存利用率;不可变对象因为有固定不变,可以作为常量来安全使用。
@GwtCompatible(emulated = true) public final class CacheBuilder<K, V> {