Java 8中一种优雅的方式向Map中添加非值元素?

5

我正在使用不可变映射(immutable map)

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

在某些情况下,getFooType()getBarType() 会返回 null。这会导致从 com.google.common.collect.ImmutableMap 抛出异常。我想知道是否有一种优雅的方法只使用非空且非空字符串填充 Map。
我可以使用任何 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检查使代码看起来不够美观。我想知道是否有更优雅的方式来处理。

我正在使用Java 8进行我的项目。


这些 getFooTypegetBarType 是静态方法吗? - Jorn Vernee
进入地图的项目的来源是什么? - bradimus
它们不是静态方法。传递给映射的项来自方法调用。该方法应返回映射。 - brain storm
您需要将地图设置为不可变吗?使用Collections.unmodifiableMap也可以吗? - Jorn Vernee
3个回答

10
您可以将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。

在此处查看更多信息


不错。想知道 getMap() 是否可以将 Map<String, Optional<String>> 返回的结果进行后处理,转换成 Map<String,String> 类型? - brain storm
1
看一下 MapUtils(不记得是guava还是apacheCommons)- 你可以使用filter来过滤掉值为空的可选项,然后使用convert从剩余的可选项中获取值。(但如果你问我,如果可能的话,最好保留可选项) - Nir Levy

4
重复的

内容

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()类型的工厂方法中。


3

纯Java 8解决方案:

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));
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接