我目前有一个多层结构数据,如下所示:
行业类有一个可以为空的私有字段
Set<Company>。 Company类有一个可以为空的私有字段Set<Division>。 除法类有一个可以为空的私有字段Set<Group>。 Group类有一个私有字段groupName,该字段可以为null,可以使用getter (getGroupName())检索。
我试图将Industry的一个实例源源不断地流到Group层,并将所有groupName连接到一个字符串中,中间有"/“。
如果此工业实例不包含任何groupName,则返回字符串"null“。
基于我对Java 8的有限知识,我想编写如下代码:
industry.stream()
.flatmap(industry -> industry.getCompanies().stream())
.filter(Objects::nonNull)
.flatmap(company -> company.getDivisions().stream())
.filter(Objects::nonNull)
.flatmap(division -> division.getGroups().stream())
.map(group -> group.getGroupName)
.collect(Collectors.joining("/")));这段代码在某些方面似乎有缺陷。另外,我不知道该在哪里添加这样的语句:如果工业无法检索任何groupName,而不是将所有groupName连接到一个字符串中,只需返回一个字符串"null“。
在我的情况下,使用Java 8流的正确方法是什么?
谢谢。
发布于 2017-09-07 17:09:49
Collectors.joining(…)是基于类StringJoiner的。它提供了它的分隔符、前缀和后缀功能,但不幸的是它没有提供空值的能力。
要添加这个特性,我们必须重新实现Collectors.joining,谢天谢地,使用StringJoiner并不难。
更改流操作的最后一行
.collect(Collectors.joining("/"));至
.filter(Objects::nonNull) // elide all null elements
.collect(()->new StringJoiner("/", "", "").setEmptyValue("null"), // use "null" when empty
StringJoiner::add, StringJoiner::merge).toString();发布于 2017-09-07 17:35:14
我很理解你的问题,几乎任何事情都是无效的。在这种情况下,您可以创建自己的函数来处理这个问题。我做了一个这样的:
/**
* Creates a stream function for the provided collection function which ignores all null values.
* Will filter out null values passed into the collection function and null values from the resulting stream
* @param collectionFn
* @param <T>
* @param <R>
* @return
*/
public static <T, R> Function<T, Stream<R>> nullSafeMapper(Function<T, Collection<R>> collectionFn) {
return (v) -> Optional.ofNullable(v)
.map(collectionFn)
.map(Collection::stream)
.orElse(Stream.empty())
.filter(Objects::nonNull);
}基本上它是完全空安全的,过滤掉输入和输出中的空值。并可作为下列用途:
industries.stream()
.flatMap(SO46101593.nullSafeMapper(Industry::getCompanies))
.flatMap(SO46101593.nullSafeMapper(Company::getDivisions))
.flatMap(SO46101593.nullSafeMapper(Division::getGroups))
.map(group -> group.getGroupName())
.filter(Objects::nonNull) // filter out null group names
.collect(Collectors.joining("/"));你也可以把这个逻辑直接推到你的表达式中,但是由于它必须重复3次,所以它会变得有点.冗长重复
发布于 2017-09-07 17:36:27
下面是一个带有空检查的示例:
String s = industries.stream()
.filter( i -> i.getCompanies() != null ).flatMap( i -> i.getCompanies().stream() )
.filter( c -> c != null && c.getDivisions() != null ).flatMap( c -> c.getDivisions().stream() )
.filter( d -> d != null && d.getGroups() != null ).flatMap( d -> d.getGroups().stream() )
.filter( g -> g != null && g.getGroupName() != null ).map( g -> g.getGroupName() )
.collect( Collectors.joining("/") ); 您可以将Collectors.joining("/")替换为Holger的示例。
https://stackoverflow.com/questions/46101593
复制相似问题