【问题标题】:How to rewrite it to functional style?如何将其重写为功能样式?
【发布时间】:2021-11-10 22:14:45
【问题描述】:

我想将一些方法转移到 java8 函数样式中。

public static String foo(List<String> arguments, List<String> conditions) {
    for (String s : conditions) {
        for (String argument : arguments) {
            if (argument.contains(s)) {
                return argument;
            }
        }
    }
    return "";
}

我目前的想法是:

public static String fooFunctional(List<String> arguments, List<String> conditions) {
    return conditions.stream()
            .flatMap(condition -> arguments.stream()
                    .filter(argument -> argument.contains(condition))
                    .findFirst()
                    .map(Stream::of)
                    .orElseGet(Stream::empty))
            .findFirst()
            .orElse("");
}

有没有比上面建议的更短的版本?

【问题讨论】:

  • 是的。只需删除.findFirst() .map(Stream::of) .orElseGet(Stream::empty)

标签: java java-8


【解决方案1】:

更新

@Holger 在 cmets 中注意到,一种更简单且与 Java 8 兼容的方法:

conditions.stream()
        .flatMap(condition -> arguments.stream()
                .filter(argument -> argument.contains(condition)))
        .findFirst().orElse("");

Java 8:

conditions.stream()
        .map(condition -> arguments.stream()
                .filter(argument -> argument.contains(condition))
                .findFirst())
        .filter(Optional::isPresent)
        .findFirst().map(Optional::get).orElse("");

Java 9+:

你可以使用Optional.stream():

conditions.stream()
        .flatMap(condition -> arguments.stream()
                .filter(argument -> argument.contains(condition))
                .findFirst().stream())
        .findFirst().orElse("");

【讨论】:

  • 当给orElse 的参数是像"" 这样的常量时,您不应该使用orElseGet。这只会不必要地增加开销。
  • Optional.stream() 不存在于预期使用的 java8 中。
  • 您的第一个选项是错误的。 map 函数中的 .orElse("") 确保它永远不会失败,因为当没有匹配时它将返回一个空字符串。所以它永远不会处理超过第一个condition。 • “Java 9+”变体过于复杂。 .findFirst().stream()limit(1) 具有相同的效果,但即使这样也已过时;无论如何,外部流的findFirst 只会采用第一个匹配项。因此,您可以将内部流简化为 stream().filter(…),这使其成为与 Java 8 兼容的解决方案。
  • @Holger 你是对的,从没想过.limit(1) 可以替代.findFirst().stream()。我更新了答案以纳入您的评论。 BTW,你知道.findFirst().stream().limit(1)之间有没有性能差异?
  • @kokodyn 您询问了功能风格,而功能风格正是表达意图,而不是讨论何时评估哪个功能。当评估顺序对获得正确结果无关紧要时,该方法是正确的。您所展示的只是一个特定 Stream 实现的一个众所周知的问题,请参阅“Why filter() after flatMap() is "not completely" lazy in Java streams?”。但这只是一个较小的性能问题,不会影响正确的结果,甚至在较新的版本中已修复。
【解决方案2】:

如果返回确切的argument 并不重要,只要其中至少包含一个condition,那么您可以通过在conditions 之前通过arguments 流式传输来缩短它。像这样:

return arguments.stream()
    .filter(argument -> conditions.stream()
        .anyMatch(condition -> argument.contains(condition)))
    .findFirst()
    .orElse("");

【讨论】:

  • @marstran 不应更改原始方法的行为。我想要完全向后兼容。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-30
  • 2012-09-16
  • 2015-07-01
  • 2021-04-28
相关资源
最近更新 更多