Java 8流非法状态异常:流已被操作或关闭

ztyzrc3y  于 2023-04-10  发布在  Java
关注(0)|答案(6)|浏览(158)

我尝试使用Stream API生成Order示例。我有一个创建订单的工厂函数,并使用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);

 ...

}

如果我使用literal(1.0)初始化Order示例,这可以正常工作。

ohtdti5x

ohtdti5x1#

答案在Stream的javadoc中(重点是我的):

一个流只能操作一次(调用中间流或终端流操作)。这就排除了“分叉”流,即同一个源馈送两个或多个管道,或者同一个流的多次遍历。流实现如果检测到流被重用,可能会抛出IllegalStateException

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

iqxoj9l9

iqxoj9l92#

正如在其他答案中所说,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);
nue99wik

nue99wik3#

As fge states,您不能(不应该)多次使用Stream
有办法解决吗?
Random#doubles(double, double)的Javadoc
生成伪随机双精度值,就好像它是使用原点和边界调用以下方法的结果:

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值时,用它来获取一个新的double值,而不是试图从DoubleStream获取它。

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

mznpcxlj

mznpcxlj4#

谢谢--这非常有帮助。我还提出了一个不同的实现,目前运行良好:

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

再次感谢!
奥莱

xesrikrc

xesrikrc5#

您的方法可以是这样的一行程序。

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

sigwle7e6#

您应该使用Supplier函数接口进行初始化,如下所示

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

然后改变你的方式得到双倍像这样

streamSupplier.get().findFirst().get()

然后它正常工作。
从帖子Stream has already been operated upon or closed Exception找到了这个方法

相关问题