使用可选值在地图中填充值

时间:2019-05-08 07:18:53

标签: java

我是Java新手,仍然在学习Optional。我知道它用于避免Null Pointer Exception。

我有一段代码要使用可选的,就像这样:

    final MetadataExtractor<FCAddress> metadataExtractor = t -> {
        final Map<String, String> metadata = new HashMap<>();
        metadata.put("senderCountryCode", t.getCountryCode());
        metadata.put("senderState", t.getState());
        metadata.put("senderPostalCode",t.getPostalCode());
        return metadata;
    };

在这里,我的用例是,如果SenderState为空,即t.getState()为空,我希望map字段为空,即不填充。

我尝试过这样的事情:

    final MetadataExtractor<FCAddress> metadataExtractor = t -> {
        final Map<String, String> metadata = new HashMap<>();
        metadata.put("senderCountryCode", t.getCountryCode());
        Optional<String> senderState = Optional.of(t.getState());
        senderState.ifPresent(metadata.put("senderState", t.getState());
        metadata.put("senderPostalCode",t.getPostalCode());
        return metadata;
    };

但是这会导致编译错误,我在哪里出错呢? 错误是:“ ifPresent (java.util.function.Consumer) 不能应用”。

4 个答案:

答案 0 :(得分:3)

您需要将使用者(lambda)传递给ifPresent:

senderState.ifPresent(state -> metadata.put("state", state);
// important: the Consumer always receive a parameter.
// An empty value `() ->` is not valid!

只有在senderState 存在(也就是说,不为null)的情况下,lambda才会被执行。

顺便说一句,使用senderState构建Optional.ofNullable(...)非常重要!否则,它将引发NPE。

查看深入的教程:https://www.baeldung.com/java-optional

答案 1 :(得分:2)

  

仍在学习Optionals。我了解它用于避免Null Pointer Exception。

不一定。它们是 mean ,它使您可以拥有表示“ nothing”的 something

关于实际的编译错误:

senderState.ifPresent(metadata.put("senderState", t.getState());

ifPresent()想要消费者。来自javadoc:

public void ifPresent(Consumer<? super T> consumer)
  

如果存在值,则使用该值调用指定的使用者,否则不执行任何操作。

metadata.put()不是使用者。那是那个地图上的普通方法调用!它将返回地图的“值”类型,即String。字符串不是消费者!

长话短说:如果您真的想在这里使用ifPresent(),那么您可能希望传递一个lambda表达式(有关示例,请参见here)。

就您而言,

senderState.ifPresent(state -> metadata.put("senderState", state));

应该做。

答案 2 :(得分:2)

在此特定代码中,Optional的使用无济于事,因为您不希望向地图添加Optional,而只跳过null值。

不创建新对象的最简单解决方案是添加t.getState()值检查,如下所示:

final MetadataExtractor<FCAddress> metadataExtractor = t -> {
    final Map<String, String> metadata = new HashMap<>();
    metadata.put("senderCountryCode", t.getCountryCode());
    if (t.getState() != null) {
       metadata.put("senderState", t.getState());
    }
    metadata.put("senderPostalCode",t.getPostalCode());
    return metadata;
};

出于研究目的, GhostCat 的解决方案与Optional一起使用:

  

senderState.ifPresent(() -> metadata.put("senderState", t.getState());

完整的示例将是:

final MetadataExtractor<FCAddress> metadataExtractor = t -> {
    final Map<String, String> metadata = new HashMap<>();
    metadata.put("senderCountryCode", t.getCountryCode());

    // Here you create a not useful object that can be replaced with a simple if
    Optional<String> senderState = Optional.ofNullable(t.getState());

    // Here you create a second not necessary object because a lambda
    // espression is an instance of an anonimous class implementing
    // the corresponding interface
    senderState.ifPresent(() -> 
         metadata.put("senderState", t.getState()
    );
    metadata.put("senderPostalCode",t.getPostalCode());
    return metadata;
};

请注意,此解决方案将创建两个不必要的对象:

  • 显式Optional senderState
  • 和另一个Consumer对象,该对象在ifPresent方法内被创建为lambda表达式

答案 3 :(得分:2)

仅提供一种完全不同的方法来解决该问题:

将所有内容放入地图,然后在以下位置删除空值:

metadata.values().removeIf(Objects::isNull);

从语法上讲,这很整洁,但是由于先做某事然后撤消它,而不是一开始就不做,这可能会更快,也可能不会更快。

相关问题