Java 8 Stream IllegalStateException:Stream已经被操作或关闭

时间:2015-01-16 18:29:31

标签: java java-8 java-stream data-generation

我正在尝试使用Stream API生成订单实例。我有一个创建订单的工厂函数,DoubleStream用于初始化订单金额。

private DoubleStream doubleStream = new Random().doubles(50.0, 200.0);

private Order createOrder() {
    return new Order(doubleStream.findFirst().getAsDouble());
}

@Test
public void test() {

Stream<Order> orderStream = Stream.generate(() -> {
    return createOrder();
});

orderStream.limit(10).forEach(System.out::println);

如果我使用文字(1.0)初始化Order实例,这可以正常工作。当我使用doubleStream创建一个随机数量时,抛出异常。

知道如何解决这个问题吗?

TIA,

Ole

6 个答案:

答案 0 :(得分:14)

答案在Stream的javadoc中(强调我的):

  

只应对一个流进行操作(调用中间或终端流操作)。例如,这排除了&#34;分叉&#34;流,相同的源提供两个或多个管道,或同一流的多个遍历。 如果流实现检测到正在重用,则可能会抛出IllegalStateException。

在您的代码中,您确实使用了两次流(一次在createOrder()中,另一次用于.limit().forEach()

答案 1 :(得分:4)

正如其他答案中所述,Stream是一次性项目,每次需要时都需要创建一个新的Stream

但是,毕竟,当您删除所有存储中间结果的尝试时,这并不复杂。您的整个代码可以表示为:

Random r=new Random(); // the only stateful thing to remember

// defining and executing the chain of operations:
r.doubles(50.0, 200.0).mapToObj(Order::new).limit(10).forEach(System.out::println);

甚至更简单

r.doubles(10, 50.0, 200.0).mapToObj(Order::new).forEach(System.out::println);

答案 2 :(得分:1)

As fge states,您不能(不应)多次使用Stream

  

知道如何解决这个问题吗?

来自Random#doubles(double, double)

的Javadoc
  

生成伪随机双精度值,就好像它是结果一样   使用origin和bound调用以下方法:

double nextDouble(double origin, double bound) {
    double r = nextDouble();
    r = r * (bound - origin) + origin;
    if (r >= bound) // correct for rounding
       r = Math.nextDown(bound);
    return r;
}

实施此类方法,并在每次需要时使用它来获取新的double值,而不是尝试从DoubleStream获取它。可能使用DoubleSupplier

private final Random random = new Random();
private DoubleSupplier supplier = () -> nextDouble(random, 50.0, 200.0);

private Order createOrder() {

    return new Order(supplier.getAsDouble());
}

private static double nextDouble(Random random, double origin, double bound) {
    double r = random.nextDouble();
    r = r * (bound - origin) + origin;
    if (r >= bound) // correct for rounding
        r = Math.nextDown(bound);
    return r;
}

如果您不打算重复使用nextDouble方法,则可以内联值50.0200.0

答案 3 :(得分:0)

谢谢 - 这非常有帮助。我还想出了一个现在运作良好的不同实现:

private DoubleStream doubleStream = new Random().doubles(50.0, 200.0);

private List<Order> createOrders(int numberOfOrders) {
List<Order> orders = new ArrayList<>();
doubleStream.limit(numberOfOrders).forEach((value) -> {
    Order order = new Order(value);
    orders.add(order);
});
return orders;
}

再次感谢!

奥莱

答案 4 :(得分:0)

你的方法可能是这样的单线。您需要使用mapToObj,而不是map

private List<Order> createOrders(int numberOfOrders) {
     return doubleStream.limit(numberOfOrders).mapToObj(Order::new).collect(Collectors.toList());
}

答案 5 :(得分:0)

您应该像这样使用供应商功能界面进行初始化

print('\n'.join(' '.join(str(idij) for idij in idi) for idi in ids))

改变你的方式来获得这样的双倍

Supplier<Stream<Double>> streamSupplier = () -> (new Random().doubles(50.0, 200.0).boxed());

然后它正常工作。

从帖子Stream has already been operated upon or closed Exception

找到这种方式