问题
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;
}
}
回答1:
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 easyly 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;
}
}
回答2:
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
}
来源:https://stackoverflow.com/questions/23996454/terminate-or-break-java-8-stream-loop