我有一个for循环,该循环获取通过参数传递的值,如果满足某些条件,它将创建一个新的块对象。我需要将此循环转换为Stream。我搜索了其他类似的情况,但是由于此循环的条件不是迭代器i的值,而是日期条件,因此我无法弄清楚如何限制流。而且,这些物品不是像其他示例中那样是预制的,而是在制作过程中制作的。这是代码:
class DateBlock {
final Instant from;
final Instant to;
DateBlock(Instant from, Instant to) {
this.from = from;
this.to = to;
}
public static List<DateBlock> blockize(ZonedDateTime fromDate,
ZonedDateTime toDate,
int blockSize,
ChronoUnit blockSizeUnit) {
List<DateBlock> blocks = new ArrayList<>();
boolean reachedDate = false;
for (int i = 0; !reachedDate; i++) {
ZonedDateTime minDate = fromDate.plus(i * blockSize, blockSizeUnit);
ZonedDateTime maxDate = fromDate.plus((i + 1) * blockSize, blockSizeUnit);
reachedDate = toDate.isBefore(maxDate);
blocks.add(new DateBlock(minDate.toInstant(), maxDate.toInstant()));
}
return blocks;
}
}
我需要如何进行?
答案 0 :(得分:-1)
有Stream.iterate
遍历无限流,我们可以使用它从start
创建元素,并使用某些blockSize
将元素增加ChronoUnit
。
首先,继续在(i + 1)
中生成.map(...)
天,并检查它们是否为beforeEnd
,然后如果是,则将其添加到列表blocks.add
中,以创建new DateBlock(i-1, i)
。还可以使用allMatch()
短路端子操作来停止处理。
这里的缺点是您需要检查beforeEnd
2次。考虑到在Java 9中有.takeWhile
操作。
ZonedDateTime start = ZonedDateTime.now();
ZonedDateTime end = ZonedDateTime.now().plusDays(5);
Predicate<ZonedDateTime> beforeEnd = date -> date.isBefore(end);
final long blockSize = 1;
List<DateBlock> blocks = new ArrayList<>();
Stream.iterate(start, d -> d.plus(blockSize, ChronoUnit.DAYS))
.map(d -> d.plus(1, ChronoUnit.DAYS))
.peek(i -> {
if(beforeEnd.test(i))
blocks.add(new DateBlock(i.minus(1, ChronoUnit.DAYS), i));
})
.allMatch(beforeEnd);
运行我得到类似
的日期 [DateBlock{from=2019-04-11...,to=2019-04-12...,
...,
DateBlock{from=2019-04-15...,to=2019-04-16...}]
更新
我知道人们说这种实现乍看起来并不好,只是因为java8没有合适的方法,只是看一下.takeWhile
方法看起来有多优雅。
Predicate<DateBlock> beforeEnd = dateBlock -> dateBlock.to.isBefore(end);
Stream.iterate(start, d -> d.plus(blockSize, ChronoUnit.DAYS))
.map(i -> new DateBlock(i, i.plus(1, ChronoUnit.DAYS)))
.takeWhile(beforeEnd)
.collect(Collectors.toList());