I want to loop over a huge array and do a complicated set of instructions that takes a long time. However, if more than 30 seconds have passed, I want it to give up.
ex.
If iterating the stream or array in this case is cheap compared to actually executing the operation than just use a predicate and filter whether time is over or not.
final long end = System.nanoTime() + TimeUnit.SECONDS.toNanos(30L);
myDataStructure.stream()
.filter(e -> System.nanoTime() <= end)
.forEach(e ->
{
...
});
Question is if you need to know which elements have been processed or not. With the above you have to inspect whether a side effect took place for a specific element afterwards.
As what the comments said under the OP, takeWhile/dropWhile are missed in Java 8 (will be added in Java 9). There is no any reason to try to implement the logic by exception or other codes because the code just looks so ugly and total nonscenes even it's just for practice. I think using 3rd party library is a much, much better solution, for example StreamEx
StreamEx(source).takeWhile(() -> System.currentTimeMillis() <= start + 30000)
.forEach(e -> { ... });
You can use the fact that .allMatch()
is a short-circuiting operator to terminate the stream:
final long start = System.currentTimeMillis();
myDataStructure.stream()
.allMatch(e ->
{
// your task here
return System.currentTimeMillis() <= start + 30000;
});
I would create a custom pool for that, something like:
ForkJoinPool forkJoinPool = new ForkJoinPool(1);
try {
forkJoinPool.submit(() ->
IntStream.range(1, 1_000_000).filter(x -> x > 2).boxed().collect(Collectors.toList()))
.get(30, TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
// job not done in your interval
}
Since Stream forEach
doesn't have break
, I think you can create Custom Exception for this to break
the loop:
myDataStructure.stream()
.forEach(e ->
{
if (System.currentTimeMillis() <= start + 30000) {
throw new MyTimeOutException()
}
});
and you can catch this Exception for catch this.