Java流映射if或else,带有谓词和替换值



Java流是否有一种方便的方法可以基于谓词进行映射,但如果不满足谓词,则可以映射到其他值?

假设我有Stream.of("2021", "", "2023")。我想把它映射到Stream.of(Optional.of(Year.of(2021)), Optional.empty(), Optional.of(Year.of(2023)))。我可以这样做:

Stream<String> yearStrings = Stream.of("2021", "", "2023");
Stream<Optional<Year>> yearsFound = yearStrings.map(yearString ->
!yearString.isEmpty() ? Year.parse(yearString) : null)
.map(Optional::ofNullable);

但我想做的是,使用一个假设的过滤器映射:

Stream<String> yearStrings = Stream.of("2021", "", "2023");
Stream<Optional<Year>> yearsFound = yearStrings.mapIfOrElse(not(String::isEmpty),
Year::parse, null).map(Optional::ofNullable);

当然,我可以编写自己的mapIfOrElse(Predicate<>, Function<>, T)函数与Stream.map()一起使用,但我想检查一下Java现有的武器库中是否有类似的东西我遗漏了。

没有比现有方法更好的方法了-如果将其提取到一个方法中可能会更好,但实际上就是这样。

另一种方法可能是从所有值构造Optionals,然后使用Optional.filter将空值映射到空Optionals:

yearStreams.map(Optional::of)
.map(opt -> opt.filter(Predicate.not(String::isEmpty)));

更好吗?可能不会。

另一种方法是使用Guava的Strings.emptyToNull(其他库也可用(,它首先将空字符串转换为null;然后使用Optional.ofNullable将非null和null分别转换为非空和空Optional

yearStreams.map(Strings::emptyToNull)
.map(Optional::ofNullable)

您只需使用filter进行验证,然后仅使用map

Stream<Year> yearsFound = yearStrings.filter(yearString->!yearString.isEmpty()).map(Year::parse)

很难在一个流操作中以可读的方式平稳地组合所有这些操作。

下面是一个使用Java 16mapMulti():链接的奇怪方法

Stream<Optional<Year>> yearsFound = yearStrings
.mapMulti((yearString, consumer) -> 
Optional.of(yearString).filter(s -> !s.isEmpty()).map(Year::parse)
.ifPresentOrElse(year -> consumer.accept(Optional.of(year)),
() -> consumer.accept(Optional.empty()))
);

最新更新