Repository: apache/kafka
File: clients/src/main/java/org/apache/kafka/common/utils/Utils.java (Java)

Code before:
        return result;
    }

    public static <K, V> Map<K, V> filterMap(final Map<K, V> map, final Predicate<Entry<K, V>> filterPredicate) {
        return map.entrySet().stream().filter(filterPredicate).collect(Collectors.toMap(Entry::getKey, Entry::getValue));
    }

    /**
     * Convert a properties to map. All keys in properties must be string type. Otherwise, a ConfigException is thrown.
     * @param properties to be converted
     * @return a map including all elements in properties
     */
    public static Map<String, Object> propsToMap(Properties properties) {
        try {
            final Enumeration<?> enumeration = properties.propertyNames();
            Map<String, Object> props = new HashMap<>();
            while (enumeration.hasMoreElements()) {
                Object key = enumeration.nextElement();
                String keyString = (String) key;
                Object value = (properties.get(keyString) != null) ? properties.get(keyString) : properties.getProperty(keyString);
                props.put(keyString, value);
            }
            return props;
        } catch (Exception e) {
            throw new ConfigException("Key must be a string.");
        }
    }

    /**
     * Cast a map with arbitrary type keys to be keyed on String.
     * @param inputMap A map with unknown type keys
     * @return A map with the same contents as the input map, but with String keys
     * @throws ConfigException if any key is not a String
     */
    public static Map<String, Object> castToStringObjectMap(Map<?, ?> inputMap) {
        Map<String, Object> map = new HashMap<>(inputMap.size());
        for (Map.Entry<?, ?> entry : inputMap.entrySet()) {
            if (entry.getKey() instanceof String) {
                String k = (String) entry.getKey();
                map.put(k, entry.getValue());
            } else {
                throw new ConfigException(String.valueOf(entry.getKey()), entry.getValue(), "Key must be a string.");
            }
        }
        return map;
    }

    /**
     * Convert timestamp to an epoch value
     * @param timestamp the timestamp to be converted, the accepted formats are:
     *                 (1) yyyy-MM-dd'T'HH:mm:ss.SSS, ex: 2020-11-10T16:51:38.198

Review comment (suggestion):
Rather than casting the key to a `String`, my preference would be to proactively check the type, just like `castToStringObjectMap()` does:

```suggestion
        final Enumeration<?> enumeration = properties.propertyNames();
        Map<String, Object> map = new HashMap<>();
        while (enumeration.hasMoreElements()) {
            Object key = enumeration.nextElement();

            if (key instanceof String) {
                String k = (String) key;
                map.put(k, properties.getProperty(k));
            } else {
                throw new ConfigException(String.valueOf(key), properties.get(key), "Key must be a string.");
            }
        }
        return props;
```

Code after:
        return result;
    }

    public static <K, V> Map<K, V> filterMap(final Map<K, V> map, final Predicate<Entry<K, V>> filterPredicate) {
        return map.entrySet().stream().filter(filterPredicate).collect(Collectors.toMap(Entry::getKey, Entry::getValue));
    }

    /**
     * Convert a properties to map. All keys in properties must be string type. Otherwise, a ConfigException is thrown.
     * @param properties to be converted
     * @return a map including all elements in properties
     */
    public static Map<String, Object> propsToMap(Properties properties) {
        // This try catch block is to handle the case when the Properties object has non-String keys
        // when calling the propertyNames() method. This is a workaround for the lack of a method that
        // returns all properties including defaults and does not attempt to convert all keys to Strings.
        Enumeration<?> enumeration;
        try {
            enumeration = properties.propertyNames();
        } catch (ClassCastException e) {
            throw new ConfigException("One or more keys is not a string.");
        }
        Map<String, Object> map = new HashMap<>();
        while (enumeration.hasMoreElements()) {
            String key = (String) enumeration.nextElement();
            // properties.get(key) returns null for defaults, but properties.getProperty(key) returns null for
            // non-string values. A combination of the two methods is used to cover all cases
            Object value = (properties.get(key) != null) ? properties.get(key) : properties.getProperty(key);
            map.put(key, value);
        }
        return map;
    }

    /**
     * Cast a map with arbitrary type keys to be keyed on String.
     * @param inputMap A map with unknown type keys
     * @return A map with the same contents as the input map, but with String keys
     * @throws ConfigException if any key is not a String
     */
    public static Map<String, Object> castToStringObjectMap(Map<?, ?> inputMap) {
        if (inputMap instanceof Properties) {
            return propsToMap((Properties) inputMap);
        }
        Map<String, Object> map = new HashMap<>(inputMap.size());
        for (Map.Entry<?, ?> entry : inputMap.entrySet()) {
            if (entry.getKey() instanceof String) {
                String k = (String) entry.getKey();
                map.put(k, entry.getValue());
            } else {
                throw new ConfigException(String.valueOf(entry.getKey()), entry.getValue(), "Key must be a string.");
            }