在 java 8 中向 Map 添加非值的优雅方法?

elegant way to add non-values to Map in java 8?

我正在使用不可变映射

public Map<String,String> getMap(){
        return ImmutableMap.<String,String>builder()
                .put("FOO",getFooType())
                .put("BAR", getBarType())
                .build();
    }

在某些情况下,getFooType()getBarType() 会 return 为空。这会导致 com.google.common.collect.ImmutableMap 抛出异常。我想知道是否有一种优雅的方法可以仅使用非空和非空字符串填充地图。

我可以接受任何 Map 实现,不局限于 guava 库。

我可以取消以下内容

Map<String,String> map = new HashMap<>();

String fooType = getFooType();
String barType = getBarType();

if (fooType!=null && fooType.length()>0){
    map.put("FOO", fooType);
}

if (barType!=null && barType.length()>0){
     map.put("BAR", barType);
}

由于我有很多键要添加到地图中,这种 if-checks 使代码不美观。我想知道是否有任何优雅的方法可以做到这一点。

我正在为我的项目使用 Java 8。

可以使用Optional作为地图的值:

public Map<String,Optional<String>> getMap(){
  return ImmutableMap.<String,Optional<String>>builder()
    .put("FOO",Optional.<String>ofNullable(getFooType()))
    .put("BAR", Optional.<String>ofNullable(getBarType()))
    .build();
}

这样地图将存储包装字符串的可选对象,当您从地图获取值时,使用 map.get(key).orElse(DEF_VALUE); - 这将为您提供 DEF_VALUE值。

查看更多 here

重复

if (fooType!=null) {
    map.put("FOO", fooType);
}

看起来很冗长,因为它们重复了。如果您只是将条件添加操作放入一个方法中并重用它,代码将看起来与您的初始非条件代码一样紧凑,因为它由每个所需映射的一个方法调用组成。

请注意,您可以轻松地将其与 Guava 方法结合使用:

class MyBuilder<K,V> extends ImmutableMap.Builder<K,V> {
    public MyBuilder<K, V> putIfValueNotNull(K key, V value) {
        if(value!=null) super.put(key, value);
        return this;
    }
}

public Map<String,String> getMap(){
    return new MyBuilder<String,String>()
            .putIfValueNotNull("FOO",getFooType())
            .putIfValueNotNull("BAR", getBarType())
            .build();
}

如果您喜欢那种编码风格,您可以将 MyBuilder 创建包装到 builder() 类型的工厂方法中。

纯Java8解:

public Map<String, String> getMap() {
    return Stream.of(
            new AbstractMap.SimpleEntry<>("FOO", getFooType()),
            new AbstractMap.SimpleEntry<>("BAR", getBarType())
    )
            .filter(entry -> entry.getValue() != null)
            .filter(entry -> !entry.getValue().isEmpty())
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}