Reputation: 69
I need to use Java Stream in this code, but I don't know how it to work with an empty list.
I'm trying to find something like a while
in Stream Java 8, but I can't find it.
public static List<DateBucket> bucketize(ZonedDateTime fromDate, ZonedDateTime toDate, int bucketSize, ChronoUnit bucketSizeUnit) {
List<DateBucket> buckets = new ArrayList<>();;
boolean reachedDate = false;
for (int i = 0; !reachedDate; i++) {
ZonedDateTime minDate = fromDate.plus(i * bucketSize, bucketSizeUnit);
ZonedDateTime maxDate = fromDate.plus((i + 1) * bucketSize, bucketSizeUnit);
reachedDate = toDate.isBefore(maxDate);
buckets.add(new DateBucket(minDate.toInstant(), maxDate.toInstant()));
}
return buckets;
}
I expect to avoid the for
and use Stream in the major portion of code.
Upvotes: 1
Views: 1205
Reputation: 4577
You need to use Stream.iterate
to generate a list, you need to provide two args, the first is a initial argument, and the second is a function to process the previous argument and return the next one:
public static List<DateBucket> bucketize(ZonedDateTime fromDate, ZonedDateTime toDate, int bucketSize, ChronoUnit bucketSizeUnit) {
List buckets = Stream.iterate(
new DateBucket(
fromDate.toInstant(),
fromDate.plus(bucketSize, bucketSizeUnit).toInstant()
),
(DateBucket db) -> new DateBucket(db.to, db.to.plus( bucketSize, bucketSizeUnit))
)
.limit(bucketSizeUnit.between(fromDate, toDate) / bucketSize)
.collect(Collectors.toList());
return buckets;
}
Upvotes: 0
Reputation: 11042
You can use a LongStream
to start and mapToObj()
to create your DateBucket
s:
public static List<DateBucket> bucketize(ZonedDateTime fromDate, ZonedDateTime toDate, int bucketSize, ChronoUnit bucketSizeUnit) {
return LongStream.rangeClosed(0, bucketSizeUnit.between(fromDate, toDate))
.mapToObj(i -> {
ZonedDateTime minDate = fromDate.plus(i * bucketSize, bucketSizeUnit);
ZonedDateTime maxDate = fromDate.plus((i + 1) * bucketSize, bucketSizeUnit);
return new DateBucket(minDate.toInstant(), maxDate.toInstant());
})
.filter(b -> {
ZonedDateTime maxDate = b.getMaxDate().atZone(toDate.getZone());
ZonedDateTime limitDate = toDate.plus(bucketSize, bucketSizeUnit);
return maxDate.isBefore(limitDate) || maxDate.isEqual(limitDate);
})
.collect(Collectors.toList());
}
This creates an IntStream from 0
to the max possible index between the given dates, maps each index to a DateBucket
and filters the result for the required range.
If you can use Java 9 I would recommend using IntStream.iterate()
instead of Intstream.rangeClosed()
and takeWhile()
instead of filter()
:
public static List<DateBucket> bucketize(ZonedDateTime fromDate, ZonedDateTime toDate, int bucketSize, ChronoUnit bucketSizeUnit) {
return LongStream.iterate(0, i -> i + 1)
.mapToObj(i -> {
ZonedDateTime minDate = fromDate.plus(i * bucketSize, bucketSizeUnit);
ZonedDateTime maxDate = fromDate.plus((i + 1) * bucketSize, bucketSizeUnit);
return new DateBucket(minDate.toInstant(), maxDate.toInstant());
})
.takeWhile(b -> {
ZonedDateTime maxDate = b.getMaxDate().atZone(toDate.getZone());
ZonedDateTime limitDate = toDate.plus(bucketSize, bucketSizeUnit);
return maxDate.isBefore(limitDate) || maxDate.isEqual(limitDate);
})
.collect(Collectors.toList());
}
But none of this methods will have a better performance than the solution you already have.
Upvotes: 3