30
30
import com .google .common .cache .AbstractCache .StatsCounter ;
31
31
import com .google .common .cache .LocalCache .Strength ;
32
32
import com .google .errorprone .annotations .CanIgnoreReturnValue ;
33
+ import com .google .j2objc .annotations .J2ObjCIncompatible ;
33
34
import java .lang .ref .SoftReference ;
34
35
import java .lang .ref .WeakReference ;
36
+ import java .time .Duration ;
35
37
import java .util .ConcurrentModificationException ;
36
38
import java .util .IdentityHashMap ;
37
39
import java .util .Map ;
104
106
* <pre>{@code
105
107
* LoadingCache<Key, Graph> graphs = CacheBuilder.newBuilder()
106
108
* .maximumSize(10000)
107
- * .expireAfterWrite(10, TimeUnit.MINUTES )
109
+ * .expireAfterWrite(Duration.ofMinutes(10) )
108
110
* .removalListener(MY_LISTENER)
109
111
* .build(
110
112
* new CacheLoader<Key, Graph>() {
@@ -194,10 +196,10 @@ public final class CacheBuilder<K, V> {
194
196
private static final int DEFAULT_INITIAL_CAPACITY = 16 ;
195
197
private static final int DEFAULT_CONCURRENCY_LEVEL = 4 ;
196
198
197
- @ SuppressWarnings ("GoodTime" ) // should be a java.time. Duration
199
+ @ SuppressWarnings ("GoodTime" ) // should be a Duration
198
200
private static final int DEFAULT_EXPIRATION_NANOS = 0 ;
199
201
200
- @ SuppressWarnings ("GoodTime" ) // should be a java.time. Duration
202
+ @ SuppressWarnings ("GoodTime" ) // should be a Duration
201
203
private static final int DEFAULT_REFRESH_NANOS = 0 ;
202
204
203
205
static final Supplier <? extends StatsCounter > NULL_STATS_COUNTER =
@@ -289,13 +291,13 @@ private static final class LoggerHolder {
289
291
@ CheckForNull Strength keyStrength ;
290
292
@ CheckForNull Strength valueStrength ;
291
293
292
- @ SuppressWarnings ("GoodTime" ) // should be a java.time. Duration
294
+ @ SuppressWarnings ("GoodTime" ) // should be a Duration
293
295
long expireAfterWriteNanos = UNSET_INT ;
294
296
295
- @ SuppressWarnings ("GoodTime" ) // should be a java.time. Duration
297
+ @ SuppressWarnings ("GoodTime" ) // should be a Duration
296
298
long expireAfterAccessNanos = UNSET_INT ;
297
299
298
- @ SuppressWarnings ("GoodTime" ) // should be a java.time. Duration
300
+ @ SuppressWarnings ("GoodTime" ) // should be a Duration
299
301
long refreshNanos = UNSET_INT ;
300
302
301
303
@ CheckForNull Equivalence <Object > keyEquivalence ;
@@ -711,12 +713,48 @@ Strength getValueStrength() {
711
713
*
712
714
* @param duration the length of time after an entry is created that it should be automatically
713
715
* removed
716
+ * @return this {@code CacheBuilder} instance (for chaining)
717
+ * @throws IllegalArgumentException if {@code duration} is negative
718
+ * @throws IllegalStateException if {@link #expireAfterWrite} was already set
719
+ * @throws ArithmeticException for durations greater than +/- approximately 292 years
720
+ * @since NEXT (but since 25.0 in the JRE <a
721
+ * href="https://github.com/google/guava#guava-google-core-libraries-for-java">flavor</a>)
722
+ */
723
+ @ J2ObjCIncompatible
724
+ @ GwtIncompatible // Duration
725
+ @ SuppressWarnings ({
726
+ "GoodTime" , // Duration decomposition
727
+ "Java7ApiChecker" ,
728
+ })
729
+ @ IgnoreJRERequirement // No more dangerous than wherever the caller got the Duration from
730
+ @ CanIgnoreReturnValue
731
+ public CacheBuilder <K , V > expireAfterWrite (Duration duration ) {
732
+ return expireAfterWrite (toNanosSaturated (duration ), TimeUnit .NANOSECONDS );
733
+ }
734
+
735
+ /**
736
+ * Specifies that each entry should be automatically removed from the cache once a fixed duration
737
+ * has elapsed after the entry's creation, or the most recent replacement of its value.
738
+ *
739
+ * <p>When {@code duration} is zero, this method hands off to {@link #maximumSize(long)
740
+ * maximumSize}{@code (0)}, ignoring any otherwise-specified maximum size or weight. This can be
741
+ * useful in testing, or to disable caching temporarily without a code change.
742
+ *
743
+ * <p>Expired entries may be counted in {@link Cache#size}, but will never be visible to read or
744
+ * write operations. Expired entries are cleaned up as part of the routine maintenance described
745
+ * in the class javadoc.
746
+ *
747
+ * <p>If you can represent the duration as a {@link Duration} (which should be preferred when
748
+ * feasible), use {@link #expireAfterWrite(Duration)} instead.
749
+ *
750
+ * @param duration the length of time after an entry is created that it should be automatically
751
+ * removed
714
752
* @param unit the unit that {@code duration} is expressed in
715
753
* @return this {@code CacheBuilder} instance (for chaining)
716
754
* @throws IllegalArgumentException if {@code duration} is negative
717
755
* @throws IllegalStateException if {@link #expireAfterWrite} was already set
718
756
*/
719
- @ SuppressWarnings ("GoodTime" ) // should accept a java.time. Duration
757
+ @ SuppressWarnings ("GoodTime" ) // should accept a Duration
720
758
@ CanIgnoreReturnValue
721
759
public CacheBuilder <K , V > expireAfterWrite (long duration , TimeUnit unit ) {
722
760
checkState (
@@ -733,6 +771,44 @@ long getExpireAfterWriteNanos() {
733
771
return (expireAfterWriteNanos == UNSET_INT ) ? DEFAULT_EXPIRATION_NANOS : expireAfterWriteNanos ;
734
772
}
735
773
774
+ /**
775
+ * Specifies that each entry should be automatically removed from the cache once a fixed duration
776
+ * has elapsed after the entry's creation, the most recent replacement of its value, or its last
777
+ * access. Access time is reset by all cache read and write operations (including {@code
778
+ * Cache.asMap().get(Object)} and {@code Cache.asMap().put(K, V)}), but not by {@code
779
+ * containsKey(Object)}, nor by operations on the collection-views of {@link Cache#asMap}}. So,
780
+ * for example, iterating through {@code Cache.asMap().entrySet()} does not reset access time for
781
+ * the entries you retrieve.
782
+ *
783
+ * <p>When {@code duration} is zero, this method hands off to {@link #maximumSize(long)
784
+ * maximumSize}{@code (0)}, ignoring any otherwise-specified maximum size or weight. This can be
785
+ * useful in testing, or to disable caching temporarily without a code change.
786
+ *
787
+ * <p>Expired entries may be counted in {@link Cache#size}, but will never be visible to read or
788
+ * write operations. Expired entries are cleaned up as part of the routine maintenance described
789
+ * in the class javadoc.
790
+ *
791
+ * @param duration the length of time after an entry is last accessed that it should be
792
+ * automatically removed
793
+ * @return this {@code CacheBuilder} instance (for chaining)
794
+ * @throws IllegalArgumentException if {@code duration} is negative
795
+ * @throws IllegalStateException if {@link #expireAfterAccess} was already set
796
+ * @throws ArithmeticException for durations greater than +/- approximately 292 years
797
+ * @since NEXT (but since 25.0 in the JRE <a
798
+ * href="https://github.com/google/guava#guava-google-core-libraries-for-java">flavor</a>)
799
+ */
800
+ @ J2ObjCIncompatible
801
+ @ GwtIncompatible // Duration
802
+ @ SuppressWarnings ({
803
+ "GoodTime" , // Duration decomposition
804
+ "Java7ApiChecker" ,
805
+ })
806
+ @ IgnoreJRERequirement // No more dangerous than wherever the caller got the Duration from
807
+ @ CanIgnoreReturnValue
808
+ public CacheBuilder <K , V > expireAfterAccess (Duration duration ) {
809
+ return expireAfterAccess (toNanosSaturated (duration ), TimeUnit .NANOSECONDS );
810
+ }
811
+
736
812
/**
737
813
* Specifies that each entry should be automatically removed from the cache once a fixed duration
738
814
* has elapsed after the entry's creation, the most recent replacement of its value, or its last
@@ -750,14 +826,17 @@ long getExpireAfterWriteNanos() {
750
826
* write operations. Expired entries are cleaned up as part of the routine maintenance described
751
827
* in the class javadoc.
752
828
*
829
+ * <p>If you can represent the duration as a {@link Duration} (which should be preferred when
830
+ * feasible), use {@link #expireAfterAccess(Duration)} instead.
831
+ *
753
832
* @param duration the length of time after an entry is last accessed that it should be
754
833
* automatically removed
755
834
* @param unit the unit that {@code duration} is expressed in
756
835
* @return this {@code CacheBuilder} instance (for chaining)
757
836
* @throws IllegalArgumentException if {@code duration} is negative
758
837
* @throws IllegalStateException if {@link #expireAfterAccess} was already set
759
838
*/
760
- @ SuppressWarnings ("GoodTime" ) // should accept a java.time. Duration
839
+ @ SuppressWarnings ("GoodTime" ) // should accept a Duration
761
840
@ CanIgnoreReturnValue
762
841
public CacheBuilder <K , V > expireAfterAccess (long duration , TimeUnit unit ) {
763
842
checkState (
@@ -776,6 +855,46 @@ long getExpireAfterAccessNanos() {
776
855
: expireAfterAccessNanos ;
777
856
}
778
857
858
+ /**
859
+ * Specifies that active entries are eligible for automatic refresh once a fixed duration has
860
+ * elapsed after the entry's creation, or the most recent replacement of its value. The semantics
861
+ * of refreshes are specified in {@link LoadingCache#refresh}, and are performed by calling {@link
862
+ * CacheLoader#reload}.
863
+ *
864
+ * <p>As the default implementation of {@link CacheLoader#reload} is synchronous, it is
865
+ * recommended that users of this method override {@link CacheLoader#reload} with an asynchronous
866
+ * implementation; otherwise refreshes will be performed during unrelated cache read and write
867
+ * operations.
868
+ *
869
+ * <p>Currently automatic refreshes are performed when the first stale request for an entry
870
+ * occurs. The request triggering refresh will make a synchronous call to {@link
871
+ * CacheLoader#reload}
872
+ * to obtain a future of the new value. If the returned future is already complete, it is returned
873
+ * immediately. Otherwise, the old value is returned.
874
+ *
875
+ * <p><b>Note:</b> <i>all exceptions thrown during refresh will be logged and then swallowed</i>.
876
+ *
877
+ * @param duration the length of time after an entry is created that it should be considered
878
+ * stale, and thus eligible for refresh
879
+ * @return this {@code CacheBuilder} instance (for chaining)
880
+ * @throws IllegalArgumentException if {@code duration} is negative
881
+ * @throws IllegalStateException if {@link #refreshAfterWrite} was already set
882
+ * @throws ArithmeticException for durations greater than +/- approximately 292 years
883
+ * @since NEXT (but since 25.0 in the JRE <a
884
+ * href="https://github.com/google/guava#guava-google-core-libraries-for-java">flavor</a>)
885
+ */
886
+ @ J2ObjCIncompatible
887
+ @ GwtIncompatible // Duration
888
+ @ SuppressWarnings ({
889
+ "GoodTime" , // Duration decomposition
890
+ "Java7ApiChecker" ,
891
+ })
892
+ @ IgnoreJRERequirement // No more dangerous than wherever the caller got the Duration from
893
+ @ CanIgnoreReturnValue
894
+ public CacheBuilder <K , V > refreshAfterWrite (Duration duration ) {
895
+ return refreshAfterWrite (toNanosSaturated (duration ), TimeUnit .NANOSECONDS );
896
+ }
897
+
779
898
/**
780
899
* Specifies that active entries are eligible for automatic refresh once a fixed duration has
781
900
* elapsed after the entry's creation, or the most recent replacement of its value. The semantics
@@ -795,6 +914,9 @@ long getExpireAfterAccessNanos() {
795
914
*
796
915
* <p><b>Note:</b> <i>all exceptions thrown during refresh will be logged and then swallowed</i>.
797
916
*
917
+ * <p>If you can represent the duration as a {@link Duration} (which should be preferred when
918
+ * feasible), use {@link #refreshAfterWrite(Duration)} instead.
919
+ *
798
920
* @param duration the length of time after an entry is created that it should be considered
799
921
* stale, and thus eligible for refresh
800
922
* @param unit the unit that {@code duration} is expressed in
@@ -804,7 +926,7 @@ long getExpireAfterAccessNanos() {
804
926
* @since 11.0
805
927
*/
806
928
@ GwtIncompatible // To be supported (synchronously).
807
- @ SuppressWarnings ("GoodTime" ) // should accept a java.time. Duration
929
+ @ SuppressWarnings ("GoodTime" ) // should accept a Duration
808
930
@ CanIgnoreReturnValue
809
931
public CacheBuilder <K , V > refreshAfterWrite (long duration , TimeUnit unit ) {
810
932
checkNotNull (unit );
@@ -1002,4 +1124,27 @@ public String toString() {
1002
1124
}
1003
1125
return s .toString ();
1004
1126
}
1127
+
1128
+ /**
1129
+ * Returns the number of nanoseconds of the given duration without throwing or overflowing.
1130
+ *
1131
+ * <p>Instead of throwing {@link ArithmeticException}, this method silently saturates to either
1132
+ * {@link Long#MAX_VALUE} or {@link Long#MIN_VALUE}. This behavior can be useful when decomposing
1133
+ * a duration in order to call a legacy API which requires a {@code long, TimeUnit} pair.
1134
+ */
1135
+ @ GwtIncompatible // Duration
1136
+ @ SuppressWarnings ({
1137
+ "GoodTime" , // Duration decomposition
1138
+ "Java7ApiChecker" ,
1139
+ })
1140
+ @ IgnoreJRERequirement // No more dangerous than wherever the caller got the Duration from
1141
+ private static long toNanosSaturated (Duration duration ) {
1142
+ // Using a try/catch seems lazy, but the catch block will rarely get invoked (except for
1143
+ // durations longer than approximately +/- 292 years).
1144
+ try {
1145
+ return duration .toNanos ();
1146
+ } catch (ArithmeticException tooBig ) {
1147
+ return duration .isNegative () ? Long .MIN_VALUE : Long .MAX_VALUE ;
1148
+ }
1149
+ }
1005
1150
}
0 commit comments