[SonarLint]:使这个匿名内部 class 成为 lambda

[SonarLint]: make this anonymous inner class a lambda

下面的代码有效,但我收到了来自 SonarLint 的通知,因为我在流中使用匿名 class 而不是 lambda 表达式,而且我不知道如何改进下面的代码来避免通知:

Properties prop = new Properties();
Properties temp = new Properties();
//... add some values and keys in prop and temp

prop.putAll(temp.entrySet().stream()
    .filter( entry -> !prop.containsKey(entry.getKey()))
    .map( new Function<Entry<Object, Object>, Entry<String, String>>(){ 
        @Override
        public Entry<String, String> apply(Entry<Object, Object> entry) {
            return new Entry<String, String>() {
                @Override
                public String setValue(String value) {
                    return value.trim().toLowerCase();
                }

                @Override
                public String getValue() {
                    return ((String) entry.getValue()).trim().toLowerCase();
                }

                @Override
                public String getKey() {
                    return ((String) entry.getKey()).trim().toLowerCase();
                }
            };
        }
    })
    .collect(Collectors.toMap(Entry<String,String>::getKey, Entry<String,String>::getValue)));

代码说明: 我使用 java.util 的属性 class,不幸的是,属性 returns Entry<Object, Object>entrySet 而不是 Entry<String, String>。我想 "join" 这两个属性对象将键和值小写。因此,地图允许在 Entry<String,String> 中转换 Entry<Object, Object>。这就是为什么,有一个匿名class。

声纳建议更换

prop.putAll(temp.entrySet().stream()
    .filter( entry -> !prop.containsKey(entry.getKey()))
    .map( new Function<Entry<Object, Object>, Entry<String, String>>(){ 
        @Override
        public Entry<String, String> apply(Entry<Object, Object> entry) {
            return new Entry<String, String>() {
                @Override
                public String setValue(String value) {
                    return value.trim().toLowerCase();
                }

                @Override
                public String getValue() {
                    return ((String) entry.getValue()).trim().toLowerCase();
                }

                @Override
                public String getKey() {
                    return ((String) entry.getKey()).trim().toLowerCase();
                }
            };
        }
    })
    .collect(Collectors.toMap(Entry::getKey, Entry::getValue)));

(我删除了收集器中不需要的类型参数)

prop.putAll(temp.entrySet().stream()
    .filter( entry -> !prop.containsKey(entry.getKey()))
    .map(entry -> new Entry<String, String>() { 
        @Override
        public String setValue(String value) {
            return value.trim().toLowerCase();
        }

        @Override
        public String getValue() {
            return ((String) entry.getValue()).trim().toLowerCase();
        }

        @Override
        public String getKey() {
            return ((String) entry.getKey()).trim().toLowerCase();
        }
    })
    .collect(Collectors.toMap(Entry::getKey, Entry::getValue)));

它使用 lambda 表达式替代匿名内部 class 实现 Function,而不是 Entry 实现。

不过,在这里手动实现 Entry 接口是没有意义的,尤其是在这种违反合同的方式中使用实际上不需要的 setValue 方法。您只需要一个不可变的 Entry 实例,因此,您可以创建现有 class 的实例:

prop.putAll(temp.entrySet().stream()
    .filter( entry -> !prop.containsKey(entry.getKey()))
    .map(entry -> new AbstractMap.SimpleImmutableEntry<>(
        ((String) entry.getKey()).trim().toLowerCase(),
        ((String) entry.getValue()).trim().toLowerCase()))
    .collect(Collectors.toMap(Entry::getKey, Entry::getValue)));

作为最后的改进,在传递给 toMap 收集器的函数中执行转换时,您可以完全摆脱 Entry 实例:

prop.putAll(temp.entrySet().stream()
    .filter( entry -> !prop.containsKey(entry.getKey()))
    .collect(Collectors.toMap(
        entry -> ((String) entry.getKey())  .trim().toLowerCase(),
        entry -> ((String) entry.getValue()).trim().toLowerCase())));