43 // return is somewhat arbitrary here. Since we do not necessarily track asynchronous changes,
44 // the most recent "previous" value could be different from what we return (or could even have
45 // been removed, in which case the put will re-establish). We do not and cannot guarantee more."
46 map.put(getKey(), value);47 return super.setValue(value);
48 }
49
1063 return transformer.apply(cache.data.get(key));
1064 }
1065 @Override public @Nullable CacheEntry<K, V> getEntryIfPresentQuietly(K key) {
1066 V value = transformer.apply(cache.data.get(key));1067 return (value == null) ? null : SnapshotEntry.forEntry(key, value);
1068 }
1069 @Override public Map<K, CompletableFuture<V>> refreshes() {
1060 return cache.isRecordingStats;
1061 }
1062 @Override public @Nullable V getIfPresentQuietly(K key) {
1063 return transformer.apply(cache.data.get(key));1064 }
1065 @Override public @Nullable CacheEntry<K, V> getEntryIfPresentQuietly(K key) {
1066 V value = transformer.apply(cache.data.get(key));
759 requireNonNull(filter);
760 boolean removed = false;
761 for (var entry : cache.data.entrySet()) {
762 if (filter.test(entry.getValue())) { 763 removed |= cache.remove(entry.getKey(), entry.getValue());
764 }
765 }
3976 return cache.isRecordingStats();
3977 }
3978 @Override public @Nullable V getIfPresentQuietly(K key) {
3979 return transformer.apply(cache.getIfPresentQuietly(key));3980 }
3981 @Override public @Nullable CacheEntry<K, V> getEntryIfPresentQuietly(K key) {
3982 Node<K, V> node = cache.data.get(cache.nodeFactory.newLookupKey(key));
3224 stream.takeWhile(entry -> {
3225 weightedSize = Math.addExact(weightedSize, entry.weight());
3226 return (weightedSize <= weightLimit);
3227 }).forEach(entry -> map.put(entry.getKey(), entry.getValue()));3228 return Collections.unmodifiableMap(map);
3229 }
3230 }
1310 CompletableFuture<V> future = (CompletableFuture<V>) oldValue;
1311 if (Async.isReady(future)) {
1312 @SuppressWarnings("NullAway")
1313 var refresh = cacheLoader.asyncReload(key, future.join(), executor);1314 refreshFuture[0] = requireNonNull(refresh, "Null future");
1315 } else {
1316 // no-op if load is pending
3161
3162 /** Returns an entry for the given node if it can be used externally, else null. */
3163 @Nullable CacheEntry<K, V> nodeToCacheEntry(Node<K, V> node, Function<V, V> transformer) {
3164 V value = transformer.apply(node.getValue());3165 K key = node.getKey();
3166 long now;
3167 if ((key == null) || (value == null) || !node.isAlive()
3202 @Override
3203 public Map<K, V> apply(Stream<CacheEntry<K, V>> stream) {
3204 var map = new LinkedHashMap<K, V>(calculateHashMapCapacity(expectedSize));
3205 stream.limit(limit).forEach(entry -> map.put(entry.getKey(), entry.getValue()));3206 return Collections.unmodifiableMap(map);
3207 }
3208 }
3202 @Override
3203 public Map<K, V> apply(Stream<CacheEntry<K, V>> stream) {
3204 var map = new LinkedHashMap<K, V>(calculateHashMapCapacity(expectedSize));
3205 stream.limit(limit).forEach(entry -> map.put(entry.getKey(), entry.getValue()));3206 return Collections.unmodifiableMap(map);
3207 }
3208 }
3224 stream.takeWhile(entry -> {
3225 weightedSize = Math.addExact(weightedSize, entry.weight());
3226 return (weightedSize <= weightLimit);
3227 }).forEach(entry -> map.put(entry.getKey(), entry.getValue()));3228 return Collections.unmodifiableMap(map);
3229 }
3230 }
168 @Override
169 public long expireAfterCreate(K key, CompletableFuture<V> future, long currentTime) {
170 if (isReady(future)) {
171 long duration = delegate.expireAfterCreate(key, future.join(), currentTime);172 return Math.min(duration, MAXIMUM_EXPIRY);
173 }
174 return ASYNC_EXPIRY;
179 long currentTime, long currentDuration) {
180 if (isReady(future)) {
181 long duration = (currentDuration > MAXIMUM_EXPIRY)
182 ? delegate.expireAfterCreate(key, future.join(), currentTime)183 : delegate.expireAfterUpdate(key, future.join(), currentTime, currentDuration);
184 return Math.min(duration, MAXIMUM_EXPIRY);
185 }
180 if (isReady(future)) {
181 long duration = (currentDuration > MAXIMUM_EXPIRY)
182 ? delegate.expireAfterCreate(key, future.join(), currentTime)
183 : delegate.expireAfterUpdate(key, future.join(), currentTime, currentDuration);184 return Math.min(duration, MAXIMUM_EXPIRY);
185 }
186 return ASYNC_EXPIRY;
190 public long expireAfterRead(K key, CompletableFuture<V> future,
191 long currentTime, long currentDuration) {
192 if (isReady(future)) {
193 long duration = delegate.expireAfterRead(key, future.join(), currentTime, currentDuration);194 return Math.min(duration, MAXIMUM_EXPIRY);
195 }
196 return ASYNC_EXPIRY;
141
142 @Override
143 public int weigh(K key, CompletableFuture<V> future) {
144 return isReady(future) ? delegate.weigh(key, future.join()) : 0;145 }
146
147 Object writeReplace() {
This code appears to pass a value of type java.lang.Object
where a generic typed argument would have been expected. This will cause errors such as ClassCastException
s if the value passed is not of the correct type at runtime.
Avoid passing Object
values to methods that expect generic types unless there is a very specific use case.
While it is true that Java's generic types are stored at runtime as just Object
values, this does not mean it is okay to pass or expect Object
instead of the correct type.
Java only allows one to do so by casting the receiver type of the called method to a "raw" non-generic version first.
Bad Practice
HashMap<String, Integer> hs = new HashMap<>();
((HashMap)hs).put(new Object(), 3);
// OR
((HashMap)hs).put((Object) "newkey", 3);
Note that to force this code to work, hs
needed to first be cast to a "raw" HashMap
type before we could abuse it.
Even if the type of the argument passed at runtime is correct, making the value's type Object
will increase the chances of a bad cast or some other unsupported operation occurring later on.
Recommended
Use only the intended generic type when using generics.
hs.put("String1", 3);
Exceptions
If such code is completely intentional and is accomplishing some specific goal, it may be safe to ignore this issue.