Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

terminate or break java 8 stream loop [duplicate]

I have a java 8 stream loop with the following content:

    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
                    }
                });
    }

How can I break out of loop when some condition is met? Whats the right way to close stream anyway?

UPDATE

I was misusing streams tecnique assuming that it is a loop, it is not designed for that. Here's the code I've ended up using answer provided below:

        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;
            }
        }
like image 932
vach Avatar asked Jun 02 '14 14:06

vach


People also ask

Can we use break in Java stream?

While providing a Stream with the break mechanism embedded can be useful, it may be simpler to focus on just the forEach operation. As we can see, the new custom forEach method calls a BiConsumer providing our code with both the next element and a breaker object it can use to stop the stream.

Can we use break in stream?

You can't. Just use a real for statement. Consider another approach, you just want to not execute code, so, a simple if condition inside the forEach will do the trick.

Is Java 8 stream faster than for loop?

Yes, streams are sometimes slower than loops, but they can also be equally fast; it depends on the circumstances. The point to take home is that sequential streams are no faster than loops.

How do you end a forEach loop in Java?

break from loop is not supported by forEach. If you want to break out of forEach loop, you need to throw Exception.


2 Answers

Stream.forEach is not a loop and it's not designed for being terminated using something like break. If the stream is a parallel stream the lambda body could be executed on different threads at the same time (not easy to break that and it could easily produce incorrect results).

Better use a iterator with a while loop:

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;
    }
}
like image 98
fabian Avatar answered Oct 24 '22 05:10

fabian


Well, there is no method to do this in the stream api, (as far as i know).

But if you really need it, you can use an Exception.

EDIT: For the people giving -1 to this answer I'm not advertising this as an approach one should follow, it's just an option for the cases where you need it, and it does answer the question.

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
}
like image 27
Tiago Engel Avatar answered Oct 24 '22 04:10

Tiago Engel