All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.common.base.Suppliers Maven / Gradle / Ivy

/*
 * Copyright (C) 2007 The Guava Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */

package com.google.common.base;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

import com.google.common.annotations.GwtCompatible;
import com.google.common.annotations.VisibleForTesting;
import java.io.Serializable;
import java.util.concurrent.TimeUnit;
import org.checkerframework.checker.nullness.compatqual.NullableDecl;

/**
 * Useful suppliers.
 *
 * 

All methods return serializable suppliers as long as they're given serializable parameters. * * @author Laurence Gonsalves * @author Harry Heymann * @since 2.0 */ @GwtCompatible public final class Suppliers { private Suppliers() {} /** * Returns a new supplier which is the composition of the provided function and supplier. In other * words, the new supplier's value will be computed by retrieving the value from {@code supplier}, * and then applying {@code function} to that value. Note that the resulting supplier will not * call {@code supplier} or invoke {@code function} until it is called. */ public static Supplier compose(Function function, Supplier supplier) { return new SupplierComposition<>(function, supplier); } private static class SupplierComposition implements Supplier, Serializable { final Function function; final Supplier supplier; SupplierComposition(Function function, Supplier supplier) { this.function = checkNotNull(function); this.supplier = checkNotNull(supplier); } @Override public T get() { return function.apply(supplier.get()); } @Override public boolean equals(@NullableDecl Object obj) { if (obj instanceof SupplierComposition) { SupplierComposition that = (SupplierComposition) obj; return function.equals(that.function) && supplier.equals(that.supplier); } return false; } @Override public int hashCode() { return Objects.hashCode(function, supplier); } @Override public String toString() { return "Suppliers.compose(" + function + ", " + supplier + ")"; } private static final long serialVersionUID = 0; } /** * Returns a supplier which caches the instance retrieved during the first call to {@code get()} * and returns that value on subsequent calls to {@code get()}. See: memoization * *

The returned supplier is thread-safe. The delegate's {@code get()} method will be invoked at * most once unless the underlying {@code get()} throws an exception. The supplier's serialized * form does not contain the cached value, which will be recalculated when {@code get()} is called * on the reserialized instance. * *

When the underlying delegate throws an exception then this memoizing supplier will keep * delegating calls until it returns valid data. * *

If {@code delegate} is an instance created by an earlier call to {@code memoize}, it is * returned directly. */ public static Supplier memoize(Supplier delegate) { if (delegate instanceof NonSerializableMemoizingSupplier || delegate instanceof MemoizingSupplier) { return delegate; } return delegate instanceof Serializable ? new MemoizingSupplier(delegate) : new NonSerializableMemoizingSupplier(delegate); } @VisibleForTesting static class MemoizingSupplier implements Supplier, Serializable { final Supplier delegate; transient volatile boolean initialized; // "value" does not need to be volatile; visibility piggy-backs // on volatile read of "initialized". @NullableDecl transient T value; MemoizingSupplier(Supplier delegate) { this.delegate = checkNotNull(delegate); } @Override public T get() { // A 2-field variant of Double Checked Locking. if (!initialized) { synchronized (this) { if (!initialized) { T t = delegate.get(); value = t; initialized = true; return t; } } } return value; } @Override public String toString() { return "Suppliers.memoize(" + (initialized ? "" : delegate) + ")"; } private static final long serialVersionUID = 0; } @VisibleForTesting static class NonSerializableMemoizingSupplier implements Supplier { volatile Supplier delegate; volatile boolean initialized; // "value" does not need to be volatile; visibility piggy-backs // on volatile read of "initialized". @NullableDecl T value; NonSerializableMemoizingSupplier(Supplier delegate) { this.delegate = checkNotNull(delegate); } @Override public T get() { // A 2-field variant of Double Checked Locking. if (!initialized) { synchronized (this) { if (!initialized) { T t = delegate.get(); value = t; initialized = true; // Release the delegate to GC. delegate = null; return t; } } } return value; } @Override public String toString() { Supplier delegate = this.delegate; return "Suppliers.memoize(" + (delegate == null ? "" : delegate) + ")"; } } /** * Returns a supplier that caches the instance supplied by the delegate and removes the cached * value after the specified time has passed. Subsequent calls to {@code get()} return the cached * value if the expiration time has not passed. After the expiration time, a new value is * retrieved, cached, and returned. See: memoization * *

The returned supplier is thread-safe. The supplier's serialized form does not contain the * cached value, which will be recalculated when {@code get()} is called on the reserialized * instance. The actual memoization does not happen when the underlying delegate throws an * exception. * *

When the underlying delegate throws an exception then this memoizing supplier will keep * delegating calls until it returns valid data. * * @param duration the length of time after a value is created that it should stop being returned * by subsequent {@code get()} calls * @param unit the unit that {@code duration} is expressed in * @throws IllegalArgumentException if {@code duration} is not positive * @since 2.0 */ @SuppressWarnings("GoodTime") // should accept a java.time.Duration public static Supplier memoizeWithExpiration( Supplier delegate, long duration, TimeUnit unit) { return new ExpiringMemoizingSupplier(delegate, duration, unit); } @VisibleForTesting @SuppressWarnings("GoodTime") // lots of violations static class ExpiringMemoizingSupplier implements Supplier, Serializable { final Supplier delegate; final long durationNanos; @NullableDecl transient volatile T value; // The special value 0 means "not yet initialized". transient volatile long expirationNanos; ExpiringMemoizingSupplier(Supplier delegate, long duration, TimeUnit unit) { this.delegate = checkNotNull(delegate); this.durationNanos = unit.toNanos(duration); checkArgument(duration > 0, "duration (%s %s) must be > 0", duration, unit); } @Override public T get() { // Another variant of Double Checked Locking. // // We use two volatile reads. We could reduce this to one by // putting our fields into a holder class, but (at least on x86) // the extra memory consumption and indirection are more // expensive than the extra volatile reads. long nanos = expirationNanos; long now = Platform.systemNanoTime(); if (nanos == 0 || now - nanos >= 0) { synchronized (this) { if (nanos == expirationNanos) { // recheck for lost race T t = delegate.get(); value = t; nanos = now + durationNanos; // In the very unlikely event that nanos is 0, set it to 1; // no one will notice 1 ns of tardiness. expirationNanos = (nanos == 0) ? 1 : nanos; return t; } } } return value; } @Override public String toString() { // This is a little strange if the unit the user provided was not NANOS, // but we don't want to store the unit just for toString return "Suppliers.memoizeWithExpiration(" + delegate + ", " + durationNanos + ", NANOS)"; } private static final long serialVersionUID = 0; } /** Returns a supplier that always supplies {@code instance}. */ public static Supplier ofInstance(@NullableDecl T instance) { return new SupplierOfInstance(instance); } private static class SupplierOfInstance implements Supplier, Serializable { @NullableDecl final T instance; SupplierOfInstance(@NullableDecl T instance) { this.instance = instance; } @Override public T get() { return instance; } @Override public boolean equals(@NullableDecl Object obj) { if (obj instanceof SupplierOfInstance) { SupplierOfInstance that = (SupplierOfInstance) obj; return Objects.equal(instance, that.instance); } return false; } @Override public int hashCode() { return Objects.hashCode(instance); } @Override public String toString() { return "Suppliers.ofInstance(" + instance + ")"; } private static final long serialVersionUID = 0; } /** * Returns a supplier whose {@code get()} method synchronizes on {@code delegate} before calling * it, making it thread-safe. */ public static Supplier synchronizedSupplier(Supplier delegate) { return new ThreadSafeSupplier(delegate); } private static class ThreadSafeSupplier implements Supplier, Serializable { final Supplier delegate; ThreadSafeSupplier(Supplier delegate) { this.delegate = checkNotNull(delegate); } @Override public T get() { synchronized (delegate) { return delegate.get(); } } @Override public String toString() { return "Suppliers.synchronizedSupplier(" + delegate + ")"; } private static final long serialVersionUID = 0; } /** * Returns a function that accepts a supplier and returns the result of invoking {@link * Supplier#get} on that supplier. * *

Java 8 users: use the method reference {@code Supplier::get} instead. * * @since 8.0 */ public static Function, T> supplierFunction() { @SuppressWarnings("unchecked") // implementation is "fully variant" SupplierFunction sf = (SupplierFunction) SupplierFunctionImpl.INSTANCE; return sf; } private interface SupplierFunction extends Function, T> {} private enum SupplierFunctionImpl implements SupplierFunction { INSTANCE; // Note: This makes T a "pass-through type" @Override public Object apply(Supplier input) { return input.get(); } @Override public String toString() { return "Suppliers.supplierFunction()"; } } }