【问题标题】:Stream API allMatch() with mulitple nullable nested objects具有多个可为空的嵌套对象的流 API anyMatch()
【发布时间】:2022-01-05 14:01:23
【问题描述】:

我正在开发一个请求验证功能,我需要检查某个字符串值是否存在于包含在对象中的属性中,该对象作为映射条目的值包含,该映射是一部分一个对象,最后我的请求正文包含一组这些对象。

为了更清楚地说明,我将仅使用重要的部分代码重新创建我的情况。

假设我的ClassA 在请求正文中收到,它具有以下属性:

@Nullable
Set<ClassB> mySet = null;

现在,我们有 ClassB,它有一个特定的 ClassC 类型的包装对象:

@Nullable 
ClassC classC;

包装类 ClassC 包含一个映射:

@Nullable
Map<String, ClassD> classDMap = new HashMap<>;

最后ClassD包含了需要检查的属性是否包含某个值:

@Nullable
String propertyForValidation;

目前我使用的代码如下所示:

public boolean isValid(ClassA body) {
  return body.getMySet().stream()
                        .allMatch(x -> x.getClassC().getClassDMap().values().stream()
                        .allMatch(y -> y.getPropertyForValidation.equals("someValue"));
}

我的代码当前的问题是,当我上面描述的某些对象为空时,它无法按预期工作,因为我得到了很多 NullPointerExceptions。我想这可以通过大量 ifs 和 null 检查来解决,但我想知道是否有更优雅的方式来使用 Stream API?

感谢所有帮助,谢谢。

【问题讨论】:

  • 你可以使用类似Optional.of(x).map(ClassB::getClassC).map(ClassC::getClassDMap).map(Map::getValues).stream().flatMap(Collection::stream)...的东西。

标签: java java-stream


【解决方案1】:

这是使用单个Stream 的解决方案。 这有点重复,但应该符合您的预期结果。

注意用法:

  • Objects#nonNull 使用方法引用检查对象的无效性
  • 文字 Stringequals 一起使用的方式,以避免最后一个 NullPointerException 可能

public boolean isValid(ClassA body) {
    return ofNullable(body.getMySet())
               .orElse(emptySet())
               .stream()
               .filter(Objects::nonNull)
               .map(ClassB::getClassC)
               .filter(Objects::nonNull)
               .map(ClassC::getClassDMap)
               .filter(Objects::nonNull)
               .flatMap(map -> map.values().stream())
               .allMatch(y -> "someValue".equals(y.getPropertyForValidation()));
}

【讨论】:

  • 您的方法有效,我刚刚添加了 ofNullable(body.getMySet()).orElse(emptySet()) ,因为如果 MySet 为空,它将失败。您可以编辑您的答案以备将来使用。
【解决方案2】:

我会尝试使用Stream.filter()。像Stream.filter(x -&gt; x!=null) 这样的东西应该可以代替if 语句(并且比if 更优雅)。

在您的情况下,恐怕在您的每个对象或字段(可以为空的)吸气剂之前有必要。但这是我会采用的最流畅的方式。

您还可以将它与 isEmpty() 方法结合用于空地图的情况。

另一种方法是在您的 getter 函数中添加if 语句。这将允许您保留您已经编写的确切流。

【讨论】:

  • 感谢您的建议,不过我已经接受了 Yassin 的方法。
【解决方案3】:

受@Turing85 评论的启发,我尝试使用Optionals 解决这个问题。我推荐这种方法,但认为在这里分享可能具有教育意义!

每个orElse(Boolean.TRUE) 的效果是在相应组件丢失/设置为空时返回true(如果丢失的组件验证失败,请将其更改为Boolean.FALSE)。如果我们可以假设在ClassDMap 上没有设置任何null 值,那么Stream::allMatch 可以直接在ClassD 上而不是Optional&lt;ClassD&gt; 上工作。幸运的是,最后的String::equals 比较提供了一个nullClassD::getPropertyForValidation 返回的值的免费检查。

public boolean isValid(ClassA body) {
   return Optional.ofNullable(body)
           .flatMap(a -> Optional.ofNullable(a.getMySet()))
           .map(Set::stream)
           .map(streamB -> streamB
                   .map(b -> Optional.ofNullable(b.getClassC()))
                   .map(opC -> opC.flatMap(c -> Optional.ofNullable(c.getClassDMap())))
                   .map(opMapD -> opMapD
                           .map(map -> map.values().stream()
                                   .map(d -> Optional.ofNullable(d))
                                   .allMatch(opD -> opD
                                           .map(d -> "someValue".equals(d.getPropertyForValidation()))
                                           .orElse(Boolean.TRUE)))
                           .orElse(Boolean.TRUE))
                   .reduce((acc, item) -> acc && item)
                   .orElse(Boolean.TRUE))
           .orElse(Boolean.TRUE);
}

【讨论】:

    猜你喜欢
    • 2021-01-14
    • 1970-01-01
    • 2016-05-29
    • 2018-10-12
    • 2020-11-22
    • 2017-09-26
    • 1970-01-01
    • 2019-02-03
    • 2022-10-12
    相关资源
    最近更新 更多