Blankj/AndroidUtilCode · error · IllegalArgumentException
The key is null.
Error message
The key is null.
What it means
DebouncingUtils.isValid(String, long) keys recent activity by a string and returns whether enough time has elapsed. It rejects an empty/null key with IllegalArgumentException because the internal KEY_MILLIS_MAP is a ConcurrentHashMap and TextUtils.isEmpty(key) covers both null and ""; an empty key would collide all debounced callers into one slot and silently suppress legitimate events.
Source
Thrown at lib/utilcode/src/main/java/com/blankj/utilcode/util/DebouncingUtils.java:61
*
* @param view The view.
* @param duration The duration.
* @return {@code true}: yes<br>{@code false}: no
*/
public static boolean isValid(@NonNull final View view, final long duration) {
return isValid(String.valueOf(view.hashCode()), duration);
}
/**
* Return whether the key is not in a jitter state.
*
* @param key The key.
* @param duration The duration.
* @return {@code true}: yes<br>{@code false}: no
*/
public static boolean isValid(@NonNull String key, final long duration) {
if (TextUtils.isEmpty(key)) {
throw new IllegalArgumentException("The key is null.");
}
if (duration < 0) {
throw new IllegalArgumentException("The duration is less than 0.");
}
long curTime = SystemClock.elapsedRealtime();
clearIfNecessary(curTime);
Long validTime = KEY_MILLIS_MAP.get(key);
if (validTime == null || curTime >= validTime) {
KEY_MILLIS_MAP.put(key, curTime + duration);
return true;
}
return false;
}
private static void clearIfNecessary(long curTime) {
if (KEY_MILLIS_MAP.size() < CACHE_SIZE) return;
for (Iterator<Map.Entry<String, Long>> it = KEY_MILLIS_MAP.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<String, Long> entry = it.next();View on GitHub (pinned to 7b4caf9e54)
Solutions
- Always derive a meaningful, non-empty key (e.g. a stable view ID, a tag, or a namespaced event name) before calling isValid.
- Guard with if (!TextUtils.isEmpty(key)) before invoking, and skip/no-op when the key is empty.
- Prefer the view overload isValid(View, long) when debouncing UI clicks — it derives the key internally.
- If the key comes from external input, validate and fall back to a deterministic default at the boundary.
Example fix
// before boolean ok = DebouncingUtils.isValid(eventName, 1000); // eventName may be "" // after String key = TextUtils.isEmpty(eventName) ? "fallback:" + viewId : eventName; boolean ok = DebouncingUtils.isValid(key, 1000);
Defensive patterns
Strategy: validation
Validate before calling
// Validate the key before debouncing
String key = eventName;
if (TextUtils.isEmpty(key)) {
key = "fallback:" + viewId; // or skip the call
}
boolean ok = DebouncingUtils.isValid(key, duration); Type guard
// Ensure a usable key
public static String nonEmptyDebounceKey(String raw, String fallback) {
return (raw == null || raw.trim().isEmpty()) ? fallback : raw;
} Try / catch
try {
boolean ok = DebouncingUtils.isValid(key, duration);
} catch (IllegalArgumentException e) {
// key was empty; substitute a stable key and retry
ok = DebouncingUtils.isValid("fallback:" + viewId, duration);
} Prevention
- Always derive a stable, non-empty key (view id, tag, or namespaced event name).
- Guard with TextUtils.isEmpty(key) before calling and fall back or skip.
- Prefer the View overload isValid(view, duration) for click debouncing.
When it happens
Trigger: Calling isValid(key, duration) where key is null, "", or whitespace-only produced by String.valueOf of a null/empty source; building a key from an object whose hash source is unset; forwarding a user-entered identifier that was never validated.
Common situations: Using String.valueOf(view.hashCode()) on a view whose hashCode is 0 and then trimming; debouncing by an analytics/event name that came back empty from a config; a per-item key derived from a missing database column; copy-paste of the view-based overload with the wrong argument.
Related errors
- The duration is less than 0.
- precision shouldn't be less than zero!
- byteSize shouldn't be less than zero!
- key must be between 1 and 256 bytes
- comparator must not be null
AI-assisted analysis of Blankj/AndroidUtilCode@7b4caf9e54 (2026-08-14).
Data as JSON: /api/errors/6b2881f76e64abea.
Report an issue: GitHub.