【问题标题】:What is an alternative to finding item with forEach from nested lists with Java 8?从 Java 8 的嵌套列表中使用 forEach 查找项目的替代方法是什么?
【发布时间】:2018-08-20 05:11:15
【问题描述】:

我需要一些替代方法以使以下代码更具可读性。 ssrFlightList 是嵌套列表。

我试过forEach

ssrFlightList.stream().forEach(
            x -> x.getSsrPassengerList().stream().forEach(
                y -> y.getSsrItemList().stream().forEach(
                    z -> z.getSsrCodeList().stream().forEach(t -> {
                        if ("BSML".equalsIgnoreCase(t.getCode())) {
                            ssrCodeListStr.set(t.getText());
                        }
                    })
                )));

这也是flatMap 的例子:

Optional<SSRItemCode> itemCode = ssrFlightList
        .stream()
        .flatMap(firstNode -> firstNode.getSsrPassengerList().stream())
        .flatMap(s -> s.getSsrItemList().stream())
        .flatMap(s -> s.getSsrCodeList().stream())
        .filter(s1 -> s1.getCode().equals("BSML"))
        .findFirst();

itemCode.isPresent() ? ssrCodeListStr.set(itemCode.get().getText());

我正在寻找另一种获取ssrCodeListStr 文本的方法。

【问题讨论】:

  • “我正在寻找另一种方法” 为什么?这两种方式有什么不足?
  • 请注意,您的第二个示例与第一个示例不同,因为第一个示例获取 last 匹配值,而第二个获取第一个匹配值。
  • 我不确定你能做得更好。您可以通过编写一个将方法引用转换为流的辅助方法来稍微缩短第二个。
  • 尼特:....findFirst().map(t -&gt; ssrCodeListStr.set(t.getText())).
  • @AndyTurner ....findFirst().ifPresent(t -&gt; ssrCodeListStr.set(t.getText()))

标签: java lambda java-8 java-stream flatmap


【解决方案1】:

没有 Java 8 魔杖可以使内容更具可读性。只需使用方法引用并给方法起有意义的名称:

ssrFlightList.stream().forEach(this::setSsrForAllPassengers);

private void setSsrForAllPassengers(Flight flight)
{
    flight.getSsrPassengerList().stream().forEach(this::setSsrForPassenger);
}

private void setSsrForPassenger(Passenger passenger)
{
    passenger.getSsrItemList().stream().forEach(this::setSsrForItem);
}

private void setSsrForItem(Item item)
{
    //etc....
}

【讨论】:

  • 这是否更具可读性是非常值得怀疑的。鉴于这些方法引入了多个不同级别的抽象,这完全违背了干净的代码概念
  • “这是否更具可读性是非常值得怀疑的” 不同意。 “鉴于这些方法引入了多个不同的抽象级别” 什么? “这完全违背了干净的代码概念” 哪个?
  • 抱歉,我指的是不同级别的抽象而不是间接。有了这个更正:p。 36 -- 每个函数的一个抽象级别(您的函数是相互依赖和嵌套的),p。 44 -- 没有副作用(你的函数设置了一些东西或一些对象,从它们的定义来看,两者都完全不明显)。即使没有这些参考,代码也比单个 flatMap 的流畅 API 更难阅读。
  • @OlegSklyar 回复。第 36 页:这里的每个函数只包含一个语句,因此它们不可能包含不同的抽象级别。 重新。第 44 页: OP 所要求的几乎必然涉及副作用。感谢您的意见,但我不想进一步讨论这个问题,因为您不知道自己在说什么。
【解决方案2】:

第一种方法的另一种方法是使用普通的旧增强 for 循环:在这种情况下,流不会增加任何价值。它们允许您省略类型 (*),而是添加许多其他语法 choss。

for (Flight x : ssrFlightList) {
  for (Passenger y : x.getSsrPassengerList()) {
    for (Ssr z : y.getSsrItemList()) {
      for (SsrCode t : z.getSsrCodeList()) {
        if ("BSML".equalsIgnoreCase(t.getCode()) {
          ssrCodeListStr.set(t.getText());
        }
      }
    }
  }
}

可读性是主观的,但我发现这比尝试使用流要少得多;而且它更灵活,因为您在循环中可以执行的操作不受限制(例如,抛出已检查的异常、中断、返回等)。

如果您确实想在这里使用一些功能性的东西,您可以考虑将这些循环拉入一个方法中,并注入一个Consumer&lt;String&gt;(或Consumer&lt;SsrCode&gt; 或其他),以允许您重用代码来做除设置之外的其他事情这个特定的领域:

findSsrCode("BSML", ssrCodeList::set);
findSsrCode("XXXX", otherField::set);

我认为flatMap 版本很好,我自己可能会使用它;但是 for 循环方法并没有什么严重的错误。


(*) 但由于 Java 10 现已发布(或即将发布),您可以在此处使用 var

【讨论】:

  • 当找到一个值时,一个合适的 break/return 退出循环,也许也不错。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-24
  • 1970-01-01
  • 2021-07-17
  • 1970-01-01
相关资源
最近更新 更多