终止或中断java 8流循环[重复]

Posted

技术标签:

【中文标题】终止或中断java 8流循环[重复]【英文标题】:terminate or break java 8 stream loop [duplicate] 【发布时间】:2014-07-22 16:25:23 【问题描述】:

我有一个包含以下内容的 java 8 流循环:

    void matchSellOrder(Market market, Order sellOrder) 
        System.out.println("selling " + market.pair() + " : " + sellOrder);

        market.buyOrders()
                .stream()
                .filter(buyOrder -> buyOrder.price >= sellOrder.price)
                .sorted(BY_ASCENDING_PRICE)
                .forEach((buyOrder) -> 
                    double tradeVolume = Math.min(buyOrder.quantity, sellOrder.quantity);
                    double price = buyOrder.price;

                    buyOrder.quantity -= tradeVolume;
                    sellOrder.quantity -= tradeVolume;

                    Trade trade = new Trade.Builder(market, price, tradeVolume, Trade.Type.SELL).build();
                    CommonUtil.convertToJSON(trade);

                    if (sellOrder.quantity == 0) 
                        System.out.println("order fulfilled");
                        // break loop there
                    
                );
    

满足某些条件时如何跳出循环? 无论如何,关闭流的正确方法是什么?

更新

我误用了流技术,假设它是一个循环,它不是为此而设计的。这是我最终使用下面提供的答案的代码:

        List<Order> applicableSortedBuyOrders = market.buyOrders()
                .stream()
                .filter(buyOrder -> buyOrder.price >= sellOrder.price)
                .sorted(BY_ASCENDING_PRICE)
                .collect(toList());

        for(Order buyOrder : applicableSortedBuyOrders)
            double tradeVolume = Math.min(buyOrder.quantity, sellOrder.quantity);
            double price = buyOrder.price;

            buyOrder.quantity -= tradeVolume;
            sellOrder.quantity -= tradeVolume;

            Trade trade = new Trade.Builder(market, price, tradeVolume, Trade.Type.SELL).build();
            CommonUtil.printAsJSON(trade);

            if (sellOrder.quantity == 0) 
                System.out.println("order fulfilled");
                break;
            
        

【问题讨论】:

这个问题是重复的,但不是很多问题,而是这个问题:***.com/questions/23308193/… 我还没有尝试过,但是...如果您在 peek() 消费者中执行您的工作,并在并发安全终止状态对象上使用 anyMatch() 谓词,该怎么办?跨度> 您可以在终端操作前放置sequential() 以避免并发问题。然后只需将forEach 替换为anyMatch 并在谓词return sellOrder.quantity == 0 内返回 【参考方案1】:

Stream.forEach 不是一个循环,也不是为使用break 之类的东西终止而设计的。如果流是并行流,则 lambda 主体可以同时在不同的线程上执行(不容易破坏它,而且很容易产生错误的结果)。

最好使用带有 while 循环的迭代器:

Iterator<BuyOrderType> iter = market.buyOrders() // replace BuyOrderType with correct type here
            .stream()
            .filter(buyOrder -> buyOrder.price >= sellOrder.price)
            .sorted(BY_ASCENDING_PRICE).iterator();
while (iter.hasNext()) 
    BuyOrderType buyOrder = iter.next()  // replace BuyOrderType with correct type here
    double tradeVolume = Math.min(buyOrder.quantity, sellOrder.quantity);
    double price = buyOrder.price;

    buyOrder.quantity -= tradeVolume;
    sellOrder.quantity -= tradeVolume;

    Trade trade = new Trade.Builder(market, price, tradeVolume, Trade.Type.SELL).build();
    CommonUtil.convertToJSON(trade);

    if (sellOrder.quantity == 0) 
        System.out.println("order fulfilled");
        break;
    

【讨论】:

谢谢,我好像误用了新功能。 P.S.两者都是同一类型的“订单” 我同意这个答案,除了第一句话。 Stream.forEach 是一个循环。不同之处在于它是内部循环,而不是外部循环。因为循环是内部的,所以不能对其调用 break。 啊,你们这些小信仰!你完全可以摆脱 lambda 循环:stream.allMatch(value -&gt; if (...) return true; /* continue */ else return false; /* break */ ); @yk4ever :告诉平行蒸汽!例如。 IntStream.range(0, 1000).boxed().parallel().allMatch(i -&gt; System.out.println(i); return i % 2 != 0; );【参考方案2】:

好吧,在流 api 中没有方法可以做到这一点,(据我所知)。

但如果你真的需要它,你可以使用异常。

编辑:对于给这个答案 -1 的人,我并不是在宣传这是一种应该遵循的方法,它只是在你需要它的情况下的一种选择,它确实回答了问题。

public class BreakException extends RuntimeException ...

try 
    market.buyOrders()
            .stream()
            .filter(buyOrder -> buyOrder.price >= sellOrder.price)
            .sorted(BY_ASCENDING_PRICE)
            .forEach((buyOrder) -> 
                double tradeVolume = Math.min(buyOrder.quantity, sellOrder.quantity);
                double price = buyOrder.price;

                buyOrder.quantity -= tradeVolume;
                sellOrder.quantity -= tradeVolume;

                Trade trade = new Trade.Builder(market, price, tradeVolume, Trade.Type.SELL).build();
                CommonUtil.convertToJSON(trade);

                if (sellOrder.quantity == 0) 
                    System.out.println("order fulfilled");
                    throw new BreakException()
                
            );
 catch (BreakException e) 
    //Stoped

【讨论】:

这也是一个选项,但据我所知,抛出和处理异常在性能方面过于昂贵,应该避免(以及上面提到的 finally 块) 不适用于并行流。

以上是关于终止或中断java 8流循环[重复]的主要内容,如果未能解决你的问题,请参考以下文章

在ResultSet.execute之后循环终止[重复]

避免( java.nio.file.AccessDeniedException )的 Java 8 Files.walk(..) 终止原因 [重复]

Java 8,流查找重复元素

Java 8流手动短路[重复]

如何在java-8中查找流类型[重复]

循环没有终止,请有人解释做错了啥[重复]