Java 8 Stream IllegalStateException: Stream 已经被操作或关闭
Java 8 Stream IllegalStateException: Stream has already been operated on or closed
我正在尝试使用 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);
如果我使用文字 (1.0) 初始化 Order 实例,则效果很好。当我使用doubleStream创建一个随机数时,抛出异常。
答案在 Stream
的 javadoc 中(强调我的):
A stream should be operated on (invoking an intermediate or terminal stream operation) only once. This rules out, for example, "forked" streams, where the same source feeds two or more pipelines, or multiple traversals of the same stream. A stream implementation may throw IllegalStateException if it detects that the stream is being reused.
并且在您的代码中,您确实使用了两次流(一次在 createOrder()
中,另一次在 .limit().forEach()
中使用
,您不能(不应该)多次食用 Stream
。
Any idea how to fix this?
来自 Random#doubles(double, double)
的 Javadoc
A pseudorandom double value is generated as if it's the result of
calling the following method with the origin and 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.0
和 200.0
.
如其他答案所述,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);
谢谢 - 这很有帮助。我还提出了一个目前运行良好的不同实现:
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;
}
再次感谢!
奥莱
你的方法可以像这样单行。您需要使用 mapToObj
,而不是 map
private List<Order> createOrders(int numberOfOrders) {
return doubleStream.limit(numberOfOrders).mapToObj(Order::new).collect(Collectors.toList());
}
您应该像这样使用 Supplier 函数接口进行初始化
Supplier<Stream<Double>> streamSupplier = () -> (new Random().doubles(50.0, 200.0).boxed());
然后改变你的方式来获得双倍的收入
streamSupplier.get().findFirst().get()
然后就正常了
从 post Stream has already been operated upon or closed Exception
中找到这种方式
我正在尝试使用 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);
如果我使用文字 (1.0) 初始化 Order 实例,则效果很好。当我使用doubleStream创建一个随机数时,抛出异常。
答案在 Stream
的 javadoc 中(强调我的):
A stream should be operated on (invoking an intermediate or terminal stream operation) only once. This rules out, for example, "forked" streams, where the same source feeds two or more pipelines, or multiple traversals of the same stream. A stream implementation may throw IllegalStateException if it detects that the stream is being reused.
并且在您的代码中,您确实使用了两次流(一次在 createOrder()
中,另一次在 .limit().forEach()
Stream
。
Any idea how to fix this?
来自 Random#doubles(double, double)
A pseudorandom double value is generated as if it's the result of calling the following method with the origin and 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.0
和 200.0
.
如其他答案所述,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);
谢谢 - 这很有帮助。我还提出了一个目前运行良好的不同实现:
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;
}
再次感谢!
奥莱
你的方法可以像这样单行。您需要使用 mapToObj
,而不是 map
private List<Order> createOrders(int numberOfOrders) {
return doubleStream.limit(numberOfOrders).mapToObj(Order::new).collect(Collectors.toList());
}
您应该像这样使用 Supplier 函数接口进行初始化
Supplier<Stream<Double>> streamSupplier = () -> (new Random().doubles(50.0, 200.0).boxed());
然后改变你的方式来获得双倍的收入
streamSupplier.get().findFirst().get()
然后就正常了
从 post Stream has already been operated upon or closed Exception
中找到这种方式