Stream API anyMatch() 具有多个可为空的嵌套对象
Stream API allMatch() with mulitple nullable nested objects
我正在处理请求验证功能,我需要检查某个字符串值是否存在于包含在对象中的 属性 中,该对象包含为映射条目的值,该地图是对象的一部分,最后我的请求正文包含一组这些对象。
为了让它更清晰,我将仅使用重要的代码部分来重现我的情况。
假设我的 ClassA
在请求正文中收到,它具有以下属性:
@Nullable
Set<ClassB> mySet = null;
现在,我们 ClassB
有一个 ClassC
类型的特定包装对象:
@Nullable
ClassC classC;
包装器 class 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"));
}
我的代码当前存在的问题是,当我上面描述的某些对象为空时,它无法按预期工作,因为我得到了很多 NullPointerException
。我想这可以通过大量 ifs 和 null 检查来解决,但我想知道是否有更优雅的方法使用 Stream API?
感谢所有帮助,谢谢。
我会尝试使用 Stream.filter()。 Stream.filter(x -> x!=null)
之类的东西应该可以代替(并且比 if
语句更优雅。
在您的情况下,恐怕在您的每个对象或字段(可为空)getters 之前都有必要。但这是我最喜欢的方式。
对于空地图的情况,您也可以将它与 isEmpty() 方法结合使用。
另一种方法是在 getter 函数中 添加 if
语句。这将允许您保留您已经编写的确切流。
这是一个使用单个 Stream
的解决方案。
它有点重复,但应该符合您的预期结果。
注意用法:
Objects#nonNull
使用方法引用检查对象的无效性
- 文字
String
首先与equals
一起使用的方式避免了最后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()));
}
受到@Turing85 评论的启发,我尝试用 Optional
s 解决这个问题。我 不 推荐这种方法,但认为在这里分享可能具有教育意义!
当相应的组件 missing/set 为空时,每个 orElse(Boolean.TRUE)
的效果是 return true(如果缺少的组件应该无法通过验证,请将其更改为 Boolean.FALSE
).如果我们可以假设在 ClassD
的 Map
上没有设置 null
值,那么 Stream::allMatch
可以直接在 ClassD
上工作而不是 Optional<ClassD>
.幸运的是,最后的 String::equals
比较提供了一个 null
免费检查 return 由 ClassD::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);
}
我正在处理请求验证功能,我需要检查某个字符串值是否存在于包含在对象中的 属性 中,该对象包含为映射条目的值,该地图是对象的一部分,最后我的请求正文包含一组这些对象。
为了让它更清晰,我将仅使用重要的代码部分来重现我的情况。
假设我的 ClassA
在请求正文中收到,它具有以下属性:
@Nullable
Set<ClassB> mySet = null;
现在,我们 ClassB
有一个 ClassC
类型的特定包装对象:
@Nullable
ClassC classC;
包装器 class 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"));
}
我的代码当前存在的问题是,当我上面描述的某些对象为空时,它无法按预期工作,因为我得到了很多 NullPointerException
。我想这可以通过大量 ifs 和 null 检查来解决,但我想知道是否有更优雅的方法使用 Stream API?
感谢所有帮助,谢谢。
我会尝试使用 Stream.filter()。 Stream.filter(x -> x!=null)
之类的东西应该可以代替(并且比 if
语句更优雅。
在您的情况下,恐怕在您的每个对象或字段(可为空)getters 之前都有必要。但这是我最喜欢的方式。
对于空地图的情况,您也可以将它与 isEmpty() 方法结合使用。
另一种方法是在 getter 函数中 添加 if
语句。这将允许您保留您已经编写的确切流。
这是一个使用单个 Stream
的解决方案。
它有点重复,但应该符合您的预期结果。
注意用法:
Objects#nonNull
使用方法引用检查对象的无效性- 文字
String
首先与equals
一起使用的方式避免了最后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()));
}
受到@Turing85 评论的启发,我尝试用 Optional
s 解决这个问题。我 不 推荐这种方法,但认为在这里分享可能具有教育意义!
当相应的组件 missing/set 为空时,每个 orElse(Boolean.TRUE)
的效果是 return true(如果缺少的组件应该无法通过验证,请将其更改为 Boolean.FALSE
).如果我们可以假设在 ClassD
的 Map
上没有设置 null
值,那么 Stream::allMatch
可以直接在 ClassD
上工作而不是 Optional<ClassD>
.幸运的是,最后的 String::equals
比较提供了一个 null
免费检查 return 由 ClassD::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);
}