{"record":{"id":"e2bab2bff3a21410","repo":"didi/DoKit","slug":"the-key-is-null","errorCode":null,"errorMessage":"The key is null.","messagePattern":"The key is null\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"Android/dokit-util/src/main/java/com/didichuxing/doraemonkit/util/DebouncingUtils.java","lineNumber":62,"sourceCode":"     *\n     * @param view     The view.\n     * @param duration The duration.\n     * @return {@code true}: yes<br>{@code false}: no\n     */\n    public static boolean isValid(@NonNull final View view, final long duration) {\n        return isValid(String.valueOf(view.hashCode()), duration);\n    }\n\n    /**\n     * Return whether the key is not in a jitter state.\n     *\n     * @param key      The key.\n     * @param duration The duration.\n     * @return {@code true}: yes<br>{@code false}: no\n     */\n    public static boolean isValid(@NonNull String key, final long duration) {\n        if (TextUtils.isEmpty(key)) {\n            throw new IllegalArgumentException(\"The key is null.\");\n        }\n        if (duration < 0) {\n            throw new IllegalArgumentException(\"The duration is less than 0.\");\n        }\n        long curTime = SystemClock.elapsedRealtime();\n        clearIfNecessary(curTime);\n        Long validTime = KEY_MILLIS_MAP.get(key);\n        if (validTime == null || curTime >= validTime) {\n            KEY_MILLIS_MAP.put(key, curTime + duration);\n            return true;\n        }\n        return false;\n    }\n\n    private static void clearIfNecessary(long curTime) {\n        if (KEY_MILLIS_MAP.size() < CACHE_SIZE) return;\n        for (Iterator<Map.Entry<String, Long>> it = KEY_MILLIS_MAP.entrySet().iterator(); it.hasNext(); ) {\n            Map.Entry<String, Long> entry = it.next();","sourceCodeStart":44,"sourceCodeEnd":80,"githubUrl":"https://github.com/didi/DoKit/blob/626827cddb2feb2f3aee87a52a064b4e5ca2bed4/Android/dokit-util/src/main/java/com/didichuxing/doraemonkit/util/DebouncingUtils.java#L44-L80","documentation":"DebouncingUtils.isValid(key, duration) implements click-debouncing keyed on a string (typically a View hash) stored in a static map with an expiry timestamp. An empty or null key cannot identify a debounce entry, so it fails fast with IllegalArgumentException('The key is null.') despite the @NonNull annotation — the annotation is not enforced at runtime in Android unless Kotlin null-checks are in play.","triggerScenarios":"Calling isValid with an empty String key: isValid(\"\", 500); or from Java with a null key that slips past @NonNull; building the key from a nullable field via String.valueOf(null) producing 'null' is fine, but concatenation of nulls or trimming can produce empty strings.","commonSituations":"Debouncing helper wrappers that accept an optional tag and default it to null/empty; dynamic keys built from view identifiers that are unset in some layout variants; Java callers ignoring the @NonNull contract.","solutions":["Always pass a non-empty key; for views use the provided isValid(view, duration) overload which derives the key from hashCode().","If the key is dynamic, fall back to a constant: key = TextUtils.isEmpty(key) ? \"default\" : key.","Add Objects.requireNonNull(key) at your call site to fail with a clearer stack trace."],"exampleFix":"// before\nDebouncingUtils.isValid(tag, 500); // tag == \"\" -> throws\n\n// after\nString safeTag = TextUtils.isEmpty(tag) ? \"global\" : tag;\nDebouncingUtils.isValid(safeTag, 500);","handlingStrategy":"validation","validationCode":"String safeKey = TextUtils.isEmpty(key) ? \"fallback_key\" : key;\nboolean valid = DebouncingUtils.isValid(safeKey, duration);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Prefer the isValid(View, duration) overload which generates the key for you.","Default dynamic keys to a constant rather than allowing empty strings."],"tags":["debounce","validation","illegal-argument"],"backgroundTag":null,"analyzedSha":"626827cddb2feb2f3aee87a52a064b4e5ca2bed4","analyzedAt":"2026-08-14T12:45:58.758Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}