【问题标题】:Reusing a stream when extra filtering is needed - Java需要额外过滤时重用流 - Java
【发布时间】:2018-05-12 09:44:25
【问题描述】:

总而言之,以下代码旨在通过第一个参数过滤第二个参数中的实体。如果在第二个参数中指定了“更改”,它应该过滤更窄的结果。

当我运行它时,我收到“IllegalStateException:流已被操作或关闭”的错误。

有没有办法可以重复使用相同的流?
我见过人们实施类似供应商>的东西,但我认为这不适用于这种情况。或者,我只是对它不够熟悉,无法理解如何使用 Supplier。

/**
     * Filters through DocumentAuditEntityListing to find existence of the entities
     * ActionEnum, ActionContextEnum, LevelEnum, & StatusEnum.
     *
     * @param audits A list of audits to search
     * @param toFind The audit entities to find
     * @return If entities found, return DocumentAudit, else null
     */
    public DocumentAudit verifyAudit(DocumentAuditEntityListing audits, DocumentAudit toFind) {
        //Filter for proper entities
        Stream stream = audits.getEntities().stream().filter(doc -> (
                doc.getAction().equals(toFind.getAction())) &&
                doc.getActionContext().equals(toFind.getActionContext()) &&
                doc.getLevel().equals(toFind.getLevel()) &&
                doc.getStatus().equals(toFind.getStatus()));

        //If changes were specified, filter further.
        if (toFind.getChanges() != null){
            stream.filter(change -> (toFind.getChanges().contains(change)));
        }

        return (DocumentAudit) stream.findFirst().orElse(null);
    }

【问题讨论】:

  • 流有终端和非终端方法。像 map 和 filter 这样的非终端方法是惰性的,这意味着它们实际上在调用终端方法之前不会做任何事情。这意味着您只需要按照@Kayaman 的说明添加过滤器来“附加”到流中,但您不会“重新使用”流,因为在您调用findFirst().orElse(null) 之前它还没有被“使用”
  • 好问题,从错误消息中理解并不是那么简单。基本上你只消费你的流一次,但这不是错误消息所说的......stackoverflow.com/a/47548077/1059372

标签: java java-8 java-stream audit


【解决方案1】:

您需要使用stream = stream.filter(change -> ...) 分配结果流。

还要使流类型安全(即Stream<DocumentAudit>)。泛型自 Java 5 以来就已存在,因此您没有理由使用原始类型。

        Stream<DocumentAudio> stream = audits.getEntities().stream()
            .filter(doc -> 
                doc.getAction().equals(toFind.getAction())) &&
                doc.getActionContext().equals(toFind.getActionContext()) &&
                doc.getLevel().equals(toFind.getLevel()) &&
                doc.getStatus().equals(toFind.getStatus());


        if (toFind.getChanges() != null){
            stream = stream.filter(change -> toFind.getChanges().contains(change));
        }

        return stream.findFirst().orElse(null);

【讨论】:

    【解决方案2】:

    Supplier 不是一个技巧,它只是用来帮助创建一个新的流。规则还是一样的——在任何情况下都不能重用流。使用Supplier 的一般方法是这样的:

     Supplier<Stream<Something>>  sup = () -> yourList.stream();
    

    因此,每次您拨打sup.get() 时,您都会收到一个新的Stream。这没有什么花哨的,只是风格问题。

    实际上,您的问题与我已经看到的问题有些不同。基本上你在做:

    Stream<Some> s = ...
    
    s.filter
    s.filter
    s.forEach
    

    而且我发现这里的错误信息有点误导,stream has already been operated upon or closed 的意思实际上是 single 终端 or 中间操作只能应用于单个Stream。如果这在错误消息中更清楚,那将更有意义。

    【讨论】:

      【解决方案3】:

      错误消息令人困惑,因为流没有被重用(只调用了一个终端操作,即findFirst())。

      但是,正如其他人指出的那样,if 块内的stream.filter(...) 应用程序正在丢失,因为该filter 操作返回的流从未分配给变量。这就是造成这种令人困惑的错误的原因。

      尽管如此,我想向您展示另一种处理此要求的方法。您可以先处理谓词,然后在准备好后将其传递给stream.filter(...) 操作,而不是有条件地应用额外的过滤器:

      Predicate<DocumentAudit> pred = doc ->
          doc.getAction().equals(toFind.getAction()) &&
          doc.getActionContext().equals(toFind.getActionContext()) &&
          doc.getLevel().equals(toFind.getLevel()) &&
          doc.getStatus().equals(toFind.getStatus());
      
      // If changes were specified, filter further.
      if (toFind.getChanges() != null) {
          pred = pred.and(change -> toFind.getChanges().contains(change));
      }
      
      return audits.getEntities().stream()
          .filter(pred)
          .findFirst()
          .orElse(null);
      

      一些cmets...

      我使用Predicate.and 来编写条件。

      您使用的是原始流并在最后一行进行转换。请不要再这样做了。我们在 2017 年...

      理想情况下,您应该使用Optional 作为方法的返回值(而不是返回找到的对象或null)。这样,您的方法的用户将提前知道该对象可能已找到或未找到。他们甚至可以使用Optional 的便捷操作来有条件地对对象执行操作,或有条件地将其映射到它的某些属性等。

      【讨论】:

        猜你喜欢
        • 2016-02-20
        • 2021-04-15
        • 2018-11-21
        • 2016-10-24
        • 1970-01-01
        • 1970-01-01
        • 2022-01-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多