It sounds like what you want to do is to implement a sort of batch processing for the data represented by your Map<String, Long> info
instance. You can then create a generator for these batches as a Stream
: This is in a way the inverse of the Stream.flatMap(...)
family of methods, but, ironically, there doesn't seem to be any idiomatic functional way of doing this and so you may have to create the batches yourself in an imperative manner — for example:
private static <T> Stream<Stream<T>> createBatchStreams(final Iterator<T> iter, final int maxBatchSize) {
final Stream.Builder<Stream<T>> resultBuilder = Stream.builder();
{
// NOTE: This logic could also be encapsulated in a Collector class
// in order to make it less imperative style
Stream.Builder<T> currentBatchBuilder = Stream.builder();
int currentBatchSize = 0;
while (iter.hasNext()) {
final T next = iter.next();
if (currentBatchSize == maxBatchSize) {
resultBuilder.add(currentBatchBuilder.build());
// Start building a new batch
currentBatchBuilder = Stream.builder();
currentBatchSize = 0;
}
currentBatchBuilder.add(next);
currentBatchSize++;
}
// Check if there is a non-empty Stream to add (e.g. if there was a
// final batch which was smaller than the others)
if (currentBatchSize > 0) {
resultBuilder.add(currentBatchBuilder.build());
}
}
return resultBuilder.build();
}
Using this method, you can then create a generator of batches of your map data, which can then be fed to your calculate(...)
function (albeit with a slightly different signature):
public static void main(final String[] args) {
final Map<String, Long> info = LongStream.range(0, 10).boxed()
.collect(Collectors.toMap(value -> "key" + value, Function.identity())); // Test data
final Stream<Stream<Entry<String, Long>>> batches = createBatchStreams(info.entrySet().iterator(), 5);
batches.forEach(batch -> {
calculate(batch);
// Do some other stuff after processing each batch
});
}
private static boolean calculate(final Stream<Entry<String, Long>> info) {
// Some calculations
}