• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ben-manes / caffeine / #5173

29 Dec 2025 05:27AM UTC coverage: 0.0% (-100.0%) from 100.0%
#5173

push

github

ben-manes
speed up development ci build

0 of 3838 branches covered (0.0%)

0 of 7869 relevant lines covered (0.0%)

0.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/caffeine/src/main/java/com/github/benmanes/caffeine/cache/Policy.java
1
/*
2
 * Copyright 2014 Ben Manes. All Rights Reserved.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
package com.github.benmanes.caffeine.cache;
17

18
import static com.github.benmanes.caffeine.cache.Caffeine.toNanosSaturated;
19

20
import java.time.Duration;
21
import java.util.Map;
22
import java.util.Optional;
23
import java.util.OptionalInt;
24
import java.util.OptionalLong;
25
import java.util.concurrent.CompletableFuture;
26
import java.util.concurrent.TimeUnit;
27
import java.util.function.BiFunction;
28
import java.util.function.Function;
29
import java.util.stream.Stream;
30

31
import org.jspecify.annotations.NullMarked;
32
import org.jspecify.annotations.Nullable;
33

34
/**
35
 * An access point for inspecting and performing low-level operations based on the cache's runtime
36
 * characteristics. These operations are optional and dependent on how the cache was constructed
37
 * and what abilities the implementation exposes.
38
 *
39
 * @param <K> the type of keys
40
 * @param <V> the type of values
41
 * @author ben.manes@gmail.com (Ben Manes)
42
 */
43
@NullMarked
44
public interface Policy<K, V> {
45

46
  /**
47
   * Returns whether the cache statistics are being accumulated.
48
   *
49
   * @return if cache statistics are being recorded
50
   */
51
  boolean isRecordingStats();
52

53
  /**
54
   * Returns the value associated with the {@code key} in this cache, or {@code null} if there is no
55
   * cached value for the {@code key}. Unlike {@link Cache#getIfPresent(Object)}, this method does
56
   * not produce any side effects such as updating statistics, the eviction policy, resetting the
57
   * expiration time, or triggering a refresh.
58
   *
59
   * @param key the key whose associated value is to be returned
60
   * @return the value to which the specified key is mapped, or {@code null} if this cache contains
61
   *         no mapping for the key
62
   * @throws NullPointerException if the specified key is null
63
   */
64
  @Nullable
65
  V getIfPresentQuietly(K key);
66

67
  /**
68
   * Returns the cache entry associated with the {@code key} in this cache, or {@code null} if there
69
   * is no cached value for the {@code key}. Unlike {@link Cache#getIfPresent(Object)}, this method
70
   * does not produce any side effects such as updating statistics, the eviction policy, resetting
71
   * the expiration time, or triggering a refresh.
72
   *
73
   * @param key the key whose associated value is to be returned
74
   * @return the entry mapping for the specified key, or {@code null} if this cache contains no
75
   *         mapping for the key
76
   * @throws NullPointerException if the specified key is null
77
   * @since 3.0.6
78
   */
79
  default @Nullable CacheEntry<K, V> getEntryIfPresentQuietly(K key) {
80
    throw new UnsupportedOperationException();
×
81
  }
82

83
  /**
84
   * Returns an unmodifiable snapshot {@link Map} view of the in-flight refresh operations.
85
   *
86
   * @return a snapshot view of the in-flight refresh operations
87
   */
88
  Map<K, CompletableFuture<V>> refreshes();
89

90
  /**
91
   * Returns access to perform operations based on the maximum size or maximum weight eviction
92
   * policy. If the cache was not constructed with a size-based bound or the implementation does
93
   * not support these operations, an empty {@link Optional} is returned.
94
   *
95
   * @return access to low-level operations for this cache if an eviction policy is used
96
   */
97
  Optional<Eviction<K, V>> eviction();
98

99
  /**
100
   * Returns access to perform operations based on the time-to-idle expiration policy. This policy
101
   * determines that an entry should be automatically removed from the cache once a fixed duration
102
   * has elapsed after the entry's creation, the most recent replacement of its value, or its last
103
   * access. Access time is reset by all cache read and write operations (including
104
   * {@code Cache.asMap().get(Object)} and {@code Cache.asMap().put(K, V)}), but not by operations
105
   * on the collection-views of {@link Cache#asMap}.
106
   * <p>
107
   * If the cache was not constructed with access-based expiration or the implementation does not
108
   * support these operations, an empty {@link Optional} is returned.
109
   *
110
   * @return access to low-level operations for this cache if a time-to-idle expiration policy is
111
   *         used
112
   */
113
  Optional<FixedExpiration<K, V>> expireAfterAccess();
114

115
  /**
116
   * Returns access to perform operations based on the time-to-live expiration policy. This policy
117
   * determines that an entry should be automatically removed from the cache once a fixed duration
118
   * has elapsed after the entry's creation, or the most recent replacement of its value.
119
   * <p>
120
   * If the cache was not constructed with write-based expiration or the implementation does not
121
   * support these operations, an empty {@link Optional} is returned.
122
   *
123
   * @return access to low-level operations for this cache if a time-to-live expiration policy is
124
   *         used
125
   */
126
  Optional<FixedExpiration<K, V>> expireAfterWrite();
127

128
  /**
129
   * Returns access to perform operations based on the variable expiration policy. This policy
130
   * determines that an entry should be automatically removed from the cache once a per-entry
131
   * duration has elapsed.
132
   * <p>
133
   * If the cache was not constructed with variable expiration or the implementation does not
134
   * support these operations, an empty {@link Optional} is returned.
135
   *
136
   * @return access to low-level operations for this cache if a variable expiration policy is used
137
   */
138
  Optional<VarExpiration<K, V>> expireVariably();
139

140
  /**
141
   * Returns access to perform operations based on the time-to-live refresh policy. This policy
142
   * determines that an entry should be automatically reloaded once a fixed duration has elapsed
143
   * after the entry's creation, or the most recent replacement of its value.
144
   * <p>
145
   * If the cache was not constructed with write-based refresh or the implementation does not
146
   * support these operations, an empty {@link Optional} is returned.
147
   *
148
   * @return access to low-level operations for this cache if a time-to-live refresh policy is used
149
   */
150
  Optional<FixedRefresh<K, V>> refreshAfterWrite();
151

152
  /**
153
   * The low-level operations for a cache with a size-based eviction policy.
154
   *
155
   * @param <K> the type of keys
156
   * @param <V> the type of values
157
   */
158
  interface Eviction<K, V> {
159

160
    /**
161
     * Returns whether the cache is bounded by a maximum size or maximum weight.
162
     *
163
     * @return if the size bounding takes into account the entry's weight
164
     */
165
    boolean isWeighted();
166

167
    /**
168
     * Returns the weight of the entry. If this cache does not use a weighted size bound or does not
169
     * support querying for the entry's weight, then the {@link OptionalInt} will be empty. In an
170
     * asynchronous cache while the future is incomplete then the weight may be zero.
171
     *
172
     * @param key the key for the entry being queried
173
     * @return the weight if the entry is present in the cache
174
     * @throws NullPointerException if the specified key is null
175
     */
176
    OptionalInt weightOf(K key);
177

178
    /**
179
     * Returns the approximate accumulated weight of entries in this cache. If this cache does not
180
     * use a weighted size bound, then the {@link OptionalLong} will be empty.
181
     *
182
     * @return the combined weight of the values in this cache
183
     */
184
    OptionalLong weightedSize();
185

186
    /**
187
     * Returns the maximum total weighted or unweighted size of this cache, depending on how the
188
     * cache was constructed. This value can be best understood by inspecting {@link #isWeighted()}.
189
     *
190
     * @return the maximum size bounding, which may be either weighted or unweighted
191
     */
192
    long getMaximum();
193

194
    /**
195
     * Specifies the maximum total size of this cache. This value may be interpreted as the weighted
196
     * or unweighted threshold size based on how this cache was constructed. If the cache currently
197
     * exceeds the new maximum size this operation eagerly evict entries until the cache shrinks to
198
     * the appropriate size.
199
     * <p>
200
     * Note that some implementations may have an internal inherent bound on the maximum total size.
201
     * If the value specified exceeds that bound, then the value is set to the internal maximum.
202
     *
203
     * @param maximum the maximum, interpreted as weighted or unweighted size depending on how this
204
     *        cache was constructed
205
     * @throws IllegalArgumentException if the maximum size specified is negative
206
     */
207
    void setMaximum(long maximum);
208

209
    /**
210
     * Returns an unmodifiable snapshot {@link Map} view of the cache with ordered traversal. The
211
     * order of iteration is from the entries least likely to be retained (coldest) to the entries
212
     * most likely to be retained (hottest). This order is determined by the eviction policy's best
213
     * guess at the time of creating this snapshot view.
214
     * <p>
215
     * Beware that obtaining the mappings is <em>NOT</em> a constant-time operation. Because of the
216
     * asynchronous nature of the page replacement policy, determining the retention ordering
217
     * requires a traversal of the entries within the eviction policy's exclusive lock.
218
     *
219
     * @param limit the maximum size of the returned map (use {@link Integer#MAX_VALUE} to disregard
220
     *        the limit)
221
     * @return a snapshot view of the cache from the coldest entry to the hottest
222
     * @throws IllegalArgumentException if the limit specified is negative
223
     */
224
    Map<K, V> coldest(int limit);
225

226
    /**
227
     * Returns an unmodifiable snapshot {@link Map} view of the cache with ordered traversal. The
228
     * order of iteration is from the entries least likely to be retained (coldest) to the entries
229
     * most likely to be retained (hottest). This order is determined by the eviction policy's best
230
     * guess at the time of creating this snapshot view. If the cache is bounded by a maximum size
231
     * rather than a maximum weight, then this method is equivalent to {@link #coldest(int)}.
232
     * <p>
233
     * Beware that obtaining the mappings is <em>NOT</em> a constant-time operation. Because of the
234
     * asynchronous nature of the page replacement policy, determining the retention ordering
235
     * requires a traversal of the entries within the eviction policy's exclusive lock.
236
     *
237
     * @param weightLimit the maximum weight of the returned map (use {@link Long#MAX_VALUE} to
238
     *        disregard the limit)
239
     * @return a snapshot view of the cache from the coldest entry to the hottest
240
     * @throws IllegalArgumentException if the limit specified is negative
241
     * @since 3.0.4
242
     */
243
    default Map<K, V> coldestWeighted(long weightLimit) {
244
      throw new UnsupportedOperationException();
×
245
    }
246

247
    /**
248
     * Returns the computed result from the ordered traversal of the cache entries. The order of
249
     * iteration is from the entries least likely to be retained (coldest) to the entries most
250
     * likely to be retained (hottest). This order is determined by the eviction policy's best guess
251
     * at the time of creating this computation.
252
     * <p>
253
     * Usage example:
254
     * {@snippet class=com.github.benmanes.caffeine.cache.Snippets
255
     *           region=eviction_coldest lang=java}
256
     * <p>
257
     * Beware that this computation is performed within the eviction policy's exclusive lock, so the
258
     * computation should be short and simple. While the computation is in progress further eviction
259
     * maintenance will be halted.
260
     *
261
     * @param <T> the type of the result of the mappingFunction
262
     * @param mappingFunction the mapping function to compute a value
263
     * @return the computed value
264
     * @throws NullPointerException if the mappingFunction is null
265
     * @throws RuntimeException or Error if the mappingFunction does so
266
     * @throws java.util.ConcurrentModificationException if the computation detectably reads or
267
     *         writes an entry in this cache
268
     * @since 3.0.6
269
     */
270
    @SuppressWarnings({"JavadocDeclaration", "JavadocReference"})
271
    default <T> T coldest(Function<Stream<CacheEntry<K, V>>, T> mappingFunction) {
272
      throw new UnsupportedOperationException();
×
273
    }
274

275
    /**
276
     * Returns an unmodifiable snapshot {@link Map} view of the cache with ordered traversal. The
277
     * order of iteration is from the entries most likely to be retained (hottest) to the entries
278
     * least likely to be retained (coldest). This order is determined by the eviction policy's best
279
     * guess at the time of creating this snapshot view.
280
     * <p>
281
     * Beware that obtaining the mappings is <em>NOT</em> a constant-time operation. Because of the
282
     * asynchronous nature of the page replacement policy, determining the retention ordering
283
     * requires a traversal of the entries within the eviction policy's exclusive lock.
284
     *
285
     * @param limit the maximum size of the returned map (use {@link Integer#MAX_VALUE} to disregard
286
     *        the limit)
287
     * @return a snapshot view of the cache from the hottest entry to the coldest
288
     * @throws IllegalArgumentException if the limit specified is negative
289
     */
290
    Map<K, V> hottest(int limit);
291

292
    /**
293
     * Returns an unmodifiable snapshot {@link Map} view of the cache with ordered traversal. The
294
     * order of iteration is from the entries most likely to be retained (hottest) to the entries
295
     * least likely to be retained (coldest). This order is determined by the eviction policy's best
296
     * guess at the time of creating this snapshot view. If the cache is bounded by a maximum size
297
     * rather than a maximum weight, then this method is equivalent to {@link #hottest(int)}.
298
     * <p>
299
     * Beware that obtaining the mappings is <em>NOT</em> a constant-time operation. Because of the
300
     * asynchronous nature of the page replacement policy, determining the retention ordering
301
     * requires a traversal of the entries within the eviction policy's exclusive lock.
302
     *
303
     * @param weightLimit the maximum weight of the returned map (use {@link Long#MAX_VALUE} to
304
     *        disregard the limit)
305
     * @return a snapshot view of the cache from the hottest entry to the coldest
306
     * @throws IllegalArgumentException if the limit specified is negative
307
     * @since 3.0.4
308
     */
309
    default Map<K, V> hottestWeighted(long weightLimit) {
310
      throw new UnsupportedOperationException();
×
311
    }
312

313
    /**
314
     * Returns the computed result from the ordered traversal of the cache entries. The order of
315
     * iteration is from the entries most likely to be retained (hottest) to the entries least
316
     * likely to be retained (coldest). This order is determined by the eviction policy's best guess
317
     * at the time of creating this computation.
318
     * <p>
319
     * Usage example:
320
     * {@snippet class=com.github.benmanes.caffeine.cache.Snippets
321
     *           region=eviction_hottest lang=java}
322
     * <p>
323
     * Beware that this computation is performed within the eviction policy's exclusive lock, so the
324
     * computation should be short and simple. While the computation is in progress further eviction
325
     * maintenance will be halted.
326
     *
327
     * @param <T> the type of the result of the mappingFunction
328
     * @param mappingFunction the mapping function to compute a value
329
     * @return the computed value
330
     * @throws NullPointerException if the mappingFunction is null
331
     * @throws RuntimeException or Error if the mappingFunction does so
332
     * @throws java.util.ConcurrentModificationException if the computation detectably reads or
333
     *         writes an entry in this cache
334
     * @since 3.0.6
335
     */
336
    @SuppressWarnings({"JavadocDeclaration", "JavadocReference"})
337
    default <T> T hottest(Function<Stream<CacheEntry<K, V>>, T> mappingFunction) {
338
      throw new UnsupportedOperationException();
×
339
    }
340
  }
341

342
  /**
343
   * The low-level operations for a cache with a fixed expiration policy.
344
   *
345
   * @param <K> the type of keys
346
   * @param <V> the type of values
347
   */
348
  interface FixedExpiration<K, V> {
349

350
    /**
351
     * Returns the age of the entry based on the expiration policy. The entry's age is the cache's
352
     * estimate of the amount of time since the entry's expiration was last reset. In an
353
     * asynchronous cache while the future is incomplete then the duration may be negative.
354
     * <p>
355
     * An expiration policy uses the age to determine if an entry is fresh or stale by comparing it
356
     * to the freshness lifetime. This is calculated as {@code fresh = freshnessLifetime > age}
357
     * where {@code freshnessLifetime = expires - currentTime}.
358
     *
359
     * @param key the key for the entry being queried
360
     * @param unit the unit that {@code age} is expressed in
361
     * @return the age if the entry is present in the cache
362
     * @throws NullPointerException if the specified key is null
363
     */
364
    OptionalLong ageOf(K key, TimeUnit unit);
365

366
    /**
367
     * Returns the age of the entry based on the expiration policy. The entry's age is the cache's
368
     * estimate of the amount of time since the entry's expiration was last reset. In an
369
     * asynchronous cache while the future is incomplete then the duration may be negative.
370
     * <p>
371
     * An expiration policy uses the age to determine if an entry is fresh or stale by comparing it
372
     * to the freshness lifetime. This is calculated as {@code fresh = freshnessLifetime > age}
373
     * where {@code freshnessLifetime = expires - currentTime}.
374
     *
375
     * @param key the key for the entry being queried
376
     * @return the age if the entry is present in the cache
377
     * @throws NullPointerException if the specified key is null
378
     */
379
    default Optional<Duration> ageOf(K key) {
380
      OptionalLong duration = ageOf(key, TimeUnit.NANOSECONDS);
×
381
      return duration.isPresent()
×
382
          ? Optional.of(Duration.ofNanos(duration.getAsLong()))
×
383
          : Optional.empty();
×
384
    }
385

386
    /**
387
     * Returns the fixed duration used to determine if an entry should be automatically removed due
388
     * to elapsing this time bound. An entry is considered fresh if its age is less than this
389
     * duration, and stale otherwise. The expiration policy determines when the entry's age is
390
     * reset.
391
     *
392
     * @param unit the unit that duration is expressed in
393
     * @return the length of time after which an entry should be automatically removed
394
     * @throws NullPointerException if the unit is null
395
     */
396
    long getExpiresAfter(TimeUnit unit);
397

398
    /**
399
     * Returns the fixed duration used to determine if an entry should be automatically removed due
400
     * to elapsing this time bound. An entry is considered fresh if its age is less than this
401
     * duration, and stale otherwise. The expiration policy determines when the entry's age is
402
     * reset.
403
     *
404
     * @return the length of time after which an entry should be automatically removed
405
     */
406
    default Duration getExpiresAfter() {
407
      return Duration.ofNanos(getExpiresAfter(TimeUnit.NANOSECONDS));
×
408
    }
409

410
    /**
411
     * Specifies that each entry should be automatically removed from the cache once a fixed
412
     * duration has elapsed. The expiration policy determines when the entry's age is reset.
413
     *
414
     * @param duration the length of time after which an entry should be automatically removed
415
     * @param unit the unit that {@code duration} is expressed in
416
     * @throws IllegalArgumentException if {@code duration} is negative
417
     * @throws NullPointerException if the unit is null
418
     */
419
    void setExpiresAfter(long duration, TimeUnit unit);
420

421
    /**
422
     * Specifies that each entry should be automatically removed from the cache once a fixed
423
     * duration has elapsed. The expiration policy determines when the entry's age is reset.
424
     *
425
     * @param duration the length of time after which an entry should be automatically removed
426
     * @throws IllegalArgumentException if {@code duration} is negative
427
     * @throws NullPointerException if the duration is null
428
     */
429
    default void setExpiresAfter(Duration duration) {
430
      setExpiresAfter(toNanosSaturated(duration), TimeUnit.NANOSECONDS);
×
431
    }
×
432

433
    /**
434
     * Returns an unmodifiable snapshot {@link Map} view of the cache with ordered traversal. The
435
     * order of iteration is from the entries most likely to expire (oldest) to the entries least
436
     * likely to expire (youngest). This order is determined by the expiration policy's best guess
437
     * at the time of creating this snapshot view.
438
     * <p>
439
     * Beware that obtaining the mappings is <em>NOT</em> a constant-time operation. Because of the
440
     * asynchronous nature of the page replacement policy, determining the retention ordering
441
     * requires a traversal of the entries.
442
     *
443
     * @param limit the maximum size of the returned map (use {@link Integer#MAX_VALUE} to disregard
444
     *        the limit)
445
     * @return a snapshot view of the cache from the oldest entry to the youngest
446
     * @throws IllegalArgumentException if the limit specified is negative
447
     */
448
    Map<K, V> oldest(int limit);
449

450
    /**
451
     * Returns the computed result from the ordered traversal of the cache entries. The order of
452
     * iteration is from the entries most likely to expire (oldest) to the entries least likely to
453
     * expire (youngest). This order is determined by the expiration policy's best guess at the time
454
     * of creating this computation.
455
     * <p>
456
     * Usage example:
457
     * {@snippet class=com.github.benmanes.caffeine.cache.Snippets
458
     *           region=expireFixed_oldest lang=java}
459
     * <p>
460
     * Beware that this computation is performed within the eviction policy's exclusive lock, so the
461
     * computation should be short and simple. While the computation is in progress further eviction
462
     * maintenance will be halted.
463
     *
464
     * @param <T> the type of the result of the mappingFunction
465
     * @param mappingFunction the mapping function to compute a value
466
     * @return the computed value
467
     * @throws NullPointerException if the mappingFunction is null
468
     * @throws RuntimeException or Error if the mappingFunction does so
469
     * @since 3.0.6
470
     */
471
    @SuppressWarnings({"JavadocDeclaration", "JavadocReference"})
472
    default <T> T oldest(Function<Stream<CacheEntry<K, V>>, T> mappingFunction) {
473
      throw new UnsupportedOperationException();
×
474
    }
475

476
    /**
477
     * Returns an unmodifiable snapshot {@link Map} view of the cache with ordered traversal. The
478
     * order of iteration is from the entries least likely to expire (youngest) to the entries most
479
     * likely to expire (oldest). This order is determined by the expiration policy's best guess at
480
     * the time of creating this snapshot view.
481
     * <p>
482
     * Beware that obtaining the mappings is <em>NOT</em> a constant-time operation. Because of the
483
     * asynchronous nature of the page replacement policy, determining the retention ordering
484
     * requires a traversal of the entries.
485
     *
486
     * @param limit the maximum size of the returned map (use {@link Integer#MAX_VALUE} to disregard
487
     *        the limit)
488
     * @return a snapshot view of the cache from the youngest entry to the oldest
489
     * @throws IllegalArgumentException if the limit specified is negative
490
     */
491
    Map<K, V> youngest(int limit);
492

493
    /**
494
     * Returns the computed result from the ordered traversal of the cache entries. The order of
495
     * iteration is from the entries least likely to expire (youngest) to the entries most likely to
496
     * expire (oldest). This order is determined by the expiration policy's best guess at the time
497
     * of creating this computation.
498
     * <p>
499
     * Usage example:
500
     * {@snippet class=com.github.benmanes.caffeine.cache.Snippets
501
     *           region=expireFixed_youngest lang=java}
502
     * <p>
503
     * Beware that this computation is performed within the eviction policy's exclusive lock, so the
504
     * computation should be short and simple. While the computation is in progress further eviction
505
     * maintenance will be halted.
506
     *
507
     * @param <T> the type of the result of the mappingFunction
508
     * @param mappingFunction the mapping function to compute a value
509
     * @return the computed value
510
     * @throws NullPointerException if the mappingFunction is null
511
     * @throws RuntimeException or Error if the mappingFunction does so
512
     * @since 3.0.6
513
     */
514
    @SuppressWarnings({"JavadocDeclaration", "JavadocReference"})
515
    default <T> T youngest(Function<Stream<CacheEntry<K, V>>, T> mappingFunction) {
516
      throw new UnsupportedOperationException();
×
517
    }
518
  }
519

520
  /**
521
   * The low-level operations for a cache with a variable expiration policy.
522
   *
523
   * @param <K> the type of keys
524
   * @param <V> the type of values
525
   */
526
  interface VarExpiration<K, V> {
527

528
    /**
529
     * Returns the duration until the entry should be automatically removed. The expiration policy
530
     * determines when the entry's duration is reset. In an asynchronous cache while the future is
531
     * incomplete then the duration may be extended into the distant future.
532
     *
533
     * @param key the key for the entry being queried
534
     * @param unit the unit that {@code age} is expressed in
535
     * @return the duration if the entry is present in the cache
536
     * @throws NullPointerException if the specified key or unit is null
537
     */
538
    OptionalLong getExpiresAfter(K key, TimeUnit unit);
539

540
    /**
541
     * Returns the duration until the entry should be automatically removed. The expiration policy
542
     * determines when the entry's duration is reset. In an asynchronous cache while the future is
543
     * incomplete then the duration may be extended into the distant future.
544
     *
545
     * @param key the key for the entry being queried
546
     * @return the duration if the entry is present in the cache
547
     * @throws NullPointerException if the specified key is null
548
     */
549
    default Optional<Duration> getExpiresAfter(K key) {
550
      OptionalLong duration = getExpiresAfter(key, TimeUnit.NANOSECONDS);
×
551
      return duration.isPresent()
×
552
          ? Optional.of(Duration.ofNanos(duration.getAsLong()))
×
553
          : Optional.empty();
×
554
    }
555

556
    /**
557
     * Specifies that the entry should be automatically removed from the cache once the duration has
558
     * elapsed. The expiration policy determines when the entry's age is reset. This method has no
559
     * effect if the mapping is absent or, in an asynchronous cache, if the future is incomplete.
560
     *
561
     * @param key the key for the entry being set
562
     * @param duration the length of time from now when the entry should be automatically removed
563
     * @param unit the unit that {@code duration} is expressed in
564
     * @throws IllegalArgumentException if {@code duration} is negative
565
     * @throws NullPointerException if the specified key or unit is null
566
     */
567
    void setExpiresAfter(K key, long duration, TimeUnit unit);
568

569
    /**
570
     * Specifies that the entry should be automatically removed from the cache once the duration has
571
     * elapsed. The expiration policy determines when the entry's age is reset. This method has no
572
     * effect if the mapping is absent or, in an asynchronous cache, if the future is incomplete.
573
     *
574
     * @param key the key for the entry being set
575
     * @param duration the length of time from now when the entry should be automatically removed
576
     * @throws IllegalArgumentException if {@code duration} is negative
577
     * @throws NullPointerException if the specified key or duration is null
578
     */
579
    default void setExpiresAfter(K key, Duration duration) {
580
      setExpiresAfter(key, toNanosSaturated(duration), TimeUnit.NANOSECONDS);
×
581
    }
×
582

583
    /**
584
     * Associates the {@code value} with the {@code key} in this cache if the specified key is not
585
     * already associated with a value. This method differs from {@link Map#putIfAbsent} by
586
     * substituting the configured {@link Expiry} with the specified duration, has no effect on the
587
     * duration if the entry was present, and returns the success rather than a value.
588
     *
589
     * @param key the key with which the specified value is to be associated
590
     * @param value value to be associated with the specified key
591
     * @param duration the length of time from now when the entry should be automatically removed
592
     * @param unit the unit that {@code duration} is expressed in
593
     * @return the previous value associated with the specified key, or {@code null} if there was no
594
     *         mapping for the key.
595
     * @throws IllegalArgumentException if {@code duration} is negative
596
     * @throws NullPointerException if the specified key, value, or unit is null
597
     */
598
    @Nullable V putIfAbsent(K key, V value, long duration, TimeUnit unit);
599

600
    /**
601
     * Associates the {@code value} with the {@code key} in this cache if the specified key is not
602
     * already associated with a value. This method differs from {@link Map#putIfAbsent} by
603
     * substituting the configured {@link Expiry} with the specified duration, has no effect on the
604
     * duration if the entry was present, and returns the success rather than a value.
605
     *
606
     * @param key the key with which the specified value is to be associated
607
     * @param value value to be associated with the specified key
608
     * @param duration the length of time from now when the entry should be automatically removed
609
     * @return the previous value associated with the specified key, or {@code null} if there was no
610
     *         mapping for the key.
611
     * @throws IllegalArgumentException if {@code duration} is negative
612
     * @throws NullPointerException if the specified key, value, or duration is null
613
     */
614
    default @Nullable V putIfAbsent(K key, V value, Duration duration) {
615
      return putIfAbsent(key, value, toNanosSaturated(duration), TimeUnit.NANOSECONDS);
×
616
    }
617

618
    /**
619
     * Associates the {@code value} with the {@code key} in this cache. If the cache previously
620
     * contained a value associated with the {@code key}, the old value is replaced by the new
621
     * {@code value}. This method differs from {@link Cache#put} by substituting the configured
622
     * {@link Expiry} with the specified duration.
623
     *
624
     * @param key the key with which the specified value is to be associated
625
     * @param value value to be associated with the specified key
626
     * @param duration the length of time from now when the entry should be automatically removed
627
     * @param unit the unit that {@code duration} is expressed in
628
     * @return the previous value associated with {@code key}, or {@code null} if there was no
629
     *         mapping for {@code key}.
630
     * @throws IllegalArgumentException if {@code duration} is negative
631
     * @throws NullPointerException if the specified key, value, or unit is null
632
     */
633
    @Nullable V put(K key, V value, long duration, TimeUnit unit);
634

635
    /**
636
     * Associates the {@code value} with the {@code key} in this cache. If the cache previously
637
     * contained a value associated with the {@code key}, the old value is replaced by the new
638
     * {@code value}. This method differs from {@link Cache#put} by substituting the
639
     * configured {@link Expiry} with the specified duration.
640
     *
641
     * @param key the key with which the specified value is to be associated
642
     * @param value value to be associated with the specified key
643
     * @param duration the length of time from now when the entry should be automatically removed
644
     * @return the previous value associated with {@code key}, or {@code null} if there was no
645
     *         mapping for {@code key}.
646
     * @throws IllegalArgumentException if {@code duration} is negative
647
     * @throws NullPointerException if the specified key, value, or duration is null
648
     */
649
    default @Nullable V put(K key, V value, Duration duration) {
650
      return put(key, value, toNanosSaturated(duration), TimeUnit.NANOSECONDS);
×
651
    }
652

653
    /**
654
     * Attempts to compute a mapping for the specified key and its current mapped value (or
655
     * {@code null} if there is no current mapping). The entire method invocation is performed
656
     * atomically. The supplied function is invoked exactly once per invocation of this method. Some
657
     * attempted update operations on this cache by other threads may be blocked while the
658
     * computation is in progress, so the computation should be short and simple. This method
659
     * differs from {@code cache.asMap().compute(key, remappingFunction)} by substituting the
660
     * configured {@link Expiry} with the specified duration.
661
     * <p>
662
     * <b>Warning:</b> the {@code remappingFunction} <b>must not</b> attempt to update any other
663
     * mappings of this cache.
664
     *
665
     * @param key key with which the specified value is to be associated
666
     * @param remappingFunction the function to compute a value
667
     * @param duration the length of time from now when the entry should be automatically removed
668
     * @return the new value associated with the specified key, or null if none
669
     * @throws IllegalArgumentException if {@code duration} is negative
670
     * @throws NullPointerException if the specified key, remappingFunction, or duration is null
671
     * @throws IllegalStateException if the computation detectably attempts a recursive update to
672
     *         this cache that would otherwise never complete
673
     * @throws RuntimeException or Error if the remappingFunction does so, in which case the mapping
674
     *         is unchanged
675
     * @since 3.0.6
676
     */
677
    default @Nullable V compute(K key,
678
        BiFunction<? super K, ? super V, ? extends @Nullable V> remappingFunction,
679
        Duration duration) {
680
      throw new UnsupportedOperationException();
×
681
    }
682

683
    /**
684
     * Returns an unmodifiable snapshot {@link Map} view of the cache with ordered traversal. The
685
     * order of iteration is from the entries most likely to expire (oldest) to the entries least
686
     * likely to expire (youngest). This order is determined by the expiration policy's best guess
687
     * at the time of creating this snapshot view.
688
     * <p>
689
     * Beware that obtaining the mappings is <em>NOT</em> a constant-time operation. Because of the
690
     * asynchronous nature of the page replacement policy, determining the retention ordering
691
     * requires a traversal of the entries.
692
     *
693
     * @param limit the maximum size of the returned map (use {@link Integer#MAX_VALUE} to disregard
694
     *        the limit)
695
     * @return a snapshot view of the cache from the oldest entry to the youngest
696
     * @throws IllegalArgumentException if the limit specified is negative
697
     */
698
    Map<K, V> oldest(int limit);
699

700
    /**
701
     * Returns the computed result from the ordered traversal of the cache entries. The order of
702
     * iteration is from the entries most likely to expire (oldest) to the entries least likely to
703
     * expire (youngest). This order is determined by the expiration policy's best guess at the time
704
     * of creating this computation.
705
     * <p>
706
     * Usage example:
707
     * {@snippet class=com.github.benmanes.caffeine.cache.Snippets
708
     *           region=expireVar_oldest lang=java}
709
     * <p>
710
     * Beware that this computation is performed within the eviction policy's exclusive lock, so the
711
     * computation should be short and simple. While the computation is in progress further eviction
712
     * maintenance will be halted.
713
     *
714
     * @param <T> the type of the result of the mappingFunction
715
     * @param mappingFunction the mapping function to compute a value
716
     * @return the computed value
717
     * @throws NullPointerException if the mappingFunction is null
718
     * @throws RuntimeException or Error if the mappingFunction does so
719
     * @since 3.0.6
720
     */
721
    @SuppressWarnings({"JavadocDeclaration", "JavadocReference"})
722
    default <T> T oldest(Function<Stream<CacheEntry<K, V>>, T> mappingFunction) {
723
      throw new UnsupportedOperationException();
×
724
    }
725

726
    /**
727
     * Returns an unmodifiable snapshot {@link Map} view of the cache with ordered traversal. The
728
     * order of iteration is from the entries least likely to expire (youngest) to the entries most
729
     * likely to expire (oldest). This order is determined by the expiration policy's best guess at
730
     * the time of creating this snapshot view.
731
     * <p>
732
     * Beware that obtaining the mappings is <em>NOT</em> a constant-time operation. Because of the
733
     * asynchronous nature of the page replacement policy, determining the retention ordering
734
     * requires a traversal of the entries.
735
     *
736
     * @param limit the maximum size of the returned map (use {@link Integer#MAX_VALUE} to disregard
737
     *        the limit)
738
     * @return a snapshot view of the cache from the youngest entry to the oldest
739
     * @throws IllegalArgumentException if the limit specified is negative
740
     */
741
    Map<K, V> youngest(int limit);
742

743
    /**
744
     * Returns the computed result from the ordered traversal of the cache entries. The order of
745
     * iteration is from the entries least likely to expire (youngest) to the entries most likely to
746
     * expire (oldest). This order is determined by the expiration policy's best guess at the time
747
     * of creating this computation.
748
     * <p>
749
     * Usage example:
750
     * {@snippet class=com.github.benmanes.caffeine.cache.Snippets
751
     *           region=expireVar_youngest lang=java}
752
     * <p>
753
     * Beware that this computation is performed within the eviction policy's exclusive lock, so the
754
     * computation should be short and simple. While the computation is in progress further eviction
755
     * maintenance will be halted.
756
     *
757
     * @param <T> the type of the result of the mappingFunction
758
     * @param mappingFunction the mapping function to compute a value
759
     * @return the computed value
760
     * @throws NullPointerException if the mappingFunction is null
761
     * @throws RuntimeException or Error if the mappingFunction does so
762
     * @since 3.0.6
763
     */
764
    @SuppressWarnings({"JavadocDeclaration", "JavadocReference"})
765
    default <T> T youngest(Function<Stream<CacheEntry<K, V>>, T> mappingFunction) {
766
      throw new UnsupportedOperationException();
×
767
    }
768
  }
769

770
  /**
771
   * The low-level operations for a cache with a fixed refresh policy.
772
   *
773
   * @param <K> the type of keys
774
   * @param <V> the type of values
775
   */
776
  interface FixedRefresh<K, V> {
777

778
    /**
779
     * Returns the age of the entry based on the refresh policy. The entry's age is the cache's
780
     * estimate of the amount of time since the entry's refresh period was last reset. In an
781
     * asynchronous cache while the future is incomplete then the duration may be negative.
782
     * <p>
783
     * A refresh policy uses the age to determine if an entry is fresh or stale by comparing it
784
     * to the freshness lifetime. This is calculated as {@code fresh = freshnessLifetime > age}
785
     * where {@code freshnessLifetime = expires - currentTime}.
786
     *
787
     * @param key the key for the entry being queried
788
     * @param unit the unit that {@code age} is expressed in
789
     * @return the age if the entry is present in the cache
790
     * @throws NullPointerException if the specified key or unit is null
791
     */
792
    OptionalLong ageOf(K key, TimeUnit unit);
793

794
    /**
795
     * Returns the age of the entry based on the refresh policy. The entry's age is the cache's
796
     * estimate of the amount of time since the entry's refresh period was last reset. In an
797
     * asynchronous cache while the future is incomplete then the duration may be negative.
798
     * <p>
799
     * A refresh policy uses the age to determine if an entry is fresh or stale by comparing it
800
     * to the freshness lifetime. This is calculated as {@code fresh = freshnessLifetime > age}
801
     * where {@code freshnessLifetime = expires - currentTime}.
802
     *
803
     * @param key the key for the entry being queried
804
     * @return the age if the entry is present in the cache
805
     * @throws NullPointerException if the specified key is null
806
     */
807
    default Optional<Duration> ageOf(K key) {
808
      OptionalLong duration = ageOf(key, TimeUnit.NANOSECONDS);
×
809
      return duration.isPresent()
×
810
          ? Optional.of(Duration.ofNanos(duration.getAsLong()))
×
811
          : Optional.empty();
×
812
    }
813

814
    /**
815
     * Returns the fixed duration used to determine if an entry should be eligible for reloading due
816
     * to elapsing this time bound. An entry is considered fresh if its age is less than this
817
     * duration, and stale otherwise. The refresh policy determines when the entry's age is
818
     * reset.
819
     *
820
     * @param unit the unit that duration is expressed in
821
     * @return the length of time after which an entry is eligible to be reloaded
822
     * @throws NullPointerException if the unit is null
823
     */
824
    long getRefreshesAfter(TimeUnit unit);
825

826
    /**
827
     * Returns the fixed duration used to determine if an entry should be eligible for reloading due
828
     * to elapsing this time bound. An entry is considered fresh if its age is less than this
829
     * duration, and stale otherwise. The refresh policy determines when the entry's age is
830
     * reset.
831
     *
832
     * @return the length of time after which an entry is eligible to be reloaded
833
     */
834
    default Duration getRefreshesAfter() {
835
      return Duration.ofNanos(getRefreshesAfter(TimeUnit.NANOSECONDS));
×
836
    }
837

838
    /**
839
     * Specifies that each entry should be eligible for reloading once a fixed duration has elapsed.
840
     * The refresh policy determines when the entry's age is reset.
841
     *
842
     * @param duration the length of time after which an entry is eligible to be reloaded
843
     * @param unit the unit that {@code duration} is expressed in
844
     * @throws IllegalArgumentException if {@code duration} is negative
845
     * @throws NullPointerException if the unit is null
846
     */
847
    void setRefreshesAfter(long duration, TimeUnit unit);
848

849
    /**
850
     * Specifies that each entry should be eligible for reloading once a fixed duration has elapsed.
851
     * The refresh policy determines when the entry's age is reset.
852
     *
853
     * @param duration the length of time after which an entry is eligible to be reloaded
854
     * @throws IllegalArgumentException if {@code duration} is negative
855
     * @throws NullPointerException if the duration is null
856
     */
857
    default void setRefreshesAfter(Duration duration) {
858
      setRefreshesAfter(toNanosSaturated(duration), TimeUnit.NANOSECONDS);
×
859
    }
×
860
  }
861

862
  /**
863
   * A key-value pair that may include policy metadata for the cached entry. Unless otherwise
864
   * specified, this is a value-based class, it can be assumed that the implementation is an
865
   * immutable snapshot of the cached data at the time of this entry's creation, and it will not
866
   * reflect changes afterward.
867
   *
868
   * @param <K> the type of keys
869
   * @param <V> the type of values
870
   */
871
  @NullMarked
872
  interface CacheEntry<K, V> extends Map.Entry<K, V> {
873

874
    /**
875
     * Returns the entry's weight. If the cache was not configured with a maximum weight then this
876
     * value is always {@code 1}.
877
     *
878
     * @return the weight if the entry
879
     */
880
    int weight();
881

882
    /**
883
     * Returns the {@link Ticker#read()} ticks for when this entry expires. If the cache was not
884
     * configured with an expiration policy then this value is roughly {@link Long#MAX_VALUE}
885
     * ticks away from the {@link #snapshotAt()} reading.
886
     *
887
     * @return the ticker reading for when the entry expires
888
     */
889
    long expiresAt();
890

891
    /**
892
     * Returns the duration between {@link #expiresAt()} and {@link #snapshotAt()}.
893
     *
894
     * @return the length of time after which the entry will be automatically removed
895
     */
896
    default Duration expiresAfter() {
897
      return Duration.ofNanos(expiresAt() - snapshotAt());
×
898
    }
899

900
    /**
901
     * Returns the {@link Ticker#read()} ticks for when this entry becomes refreshable. If the cache
902
     * was not configured with a refresh policy then this value is roughly {@link Long#MAX_VALUE}
903
     * ticks away from the {@link #snapshotAt()} reading.
904
     *
905
     * @return the ticker reading for when the entry may be refreshed
906
     */
907
    long refreshableAt();
908

909
    /**
910
     * Returns the duration between {@link #refreshableAt()} and {@link #snapshotAt()}.
911
     *
912
     * @return the length of time after which an entry is eligible to be reloaded
913
     */
914
    default Duration refreshableAfter() {
915
      return Duration.ofNanos(refreshableAt() - snapshotAt());
×
916
    }
917

918
    /**
919
     * Returns the {@link Ticker#read()} ticks for when this snapshot of the entry was taken. This
920
     * reading may be a constant if no time-based policy is configured.
921
     *
922
     * @return the ticker reading for when this snapshot of the entry was taken.
923
     */
924
    long snapshotAt();
925
  }
926
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc