Завершить или разбить java 8 stream loop
У меня есть цикл java 8 stream со следующим содержимым:
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
}
});
}
Как я могу выйти из цикла, когда выполняется какое-то условие?
Каким образом можно все-таки закрыть поток?
ОБНОВЛЕНИЕ
Я неправильно использовал потоки tecnique, полагая, что это цикл, он не предназначен для этого. Вот код, который я получил, используя ответ, приведенный ниже:
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
не является циклом, и он не предназначен для завершения с использованием чего-то вроде break
. Если поток представляет собой параллельный поток, тело лямбда может выполняться одновременно на разных потоках (это нелегко сломать, и это может легко привести к неправильным результатам).
Лучше использовать итератор с циклом 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;
}
}
Ответ 2
Ну, нет способа сделать это в потоке api (насколько я знаю).
Но если вы действительно нуждаетесь в нем, вы можете использовать Exception.
EDIT: Для людей, дающих -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
}