Java yield-like using Stream API
Several programming languages, such as Ruby or Python to name a few, provides the yield command. Yield provides an effective way, in terms of memory consumption, to create series of values, by generating such values on demand. More information on Python Yield.
Let’s consider a class or method requiring a huge amount of secure random integers. The classical approach would be to create an array or collection of such integers. Yield provides two major advantages over such approach:
- yield does not require to know the length of the series in advance.
- yield does not require to store all values in memory.
Fortunately, yield features can be used in Java 8 thanks to Stream API:
import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Date; import java.util.function.Supplier; import java.util.stream.Stream; public class Yield { private static final Integer RANDOM_INTS = 10; public static void main(String[] args) { try (Stream randomInt = generateRandomIntStream()){ Object[] randomInts = randomInt.limit(RANDOM_INTS) .sorted().toArray(); for (int i = 0; i < randomInts.length;i++) System.out.println(randomInts[i]); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } } private static Stream generateRandomIntStream() throws NoSuchAlgorithmException{ return Stream.generate(new Supplier() { final SecureRandom random = SecureRandom .getInstance("SHA1PRNG"); boolean init = false; int numGenerated = 0; @Override public Integer get() { if (!init){ random.setSeed(new Date().getTime()); init = true; System.out.println("Seeding"); } final int nextInt = random.nextInt(); System.out.println("Generated random " + numGenerated++ + ": " + nextInt); return nextInt; } }); } }
Following is the output after provided code snippet is executed:
Seeding Generated random 0: -896358073 Generated random 1: -1268521873 Generated random 2: 9627917 Generated random 3: -2106415441 Generated random 4: 935583477 Generated random 5: -1132421439 Generated random 6: -1324474601 Generated random 7: -1768257192 Generated random 8: -566921081 Generated random 9: 425501046 -2106415441 -1768257192 -1324474601 -1268521873 -1132421439 -896358073 -566921081 9627917 425501046 935583477
It is easy to see that Supplier is only instantiated one. Of course, we can take advantage of all Stream API features such as limit() and sorted().
The line randomInt.limit(RANDOM_INTS).sorted().toArray() triggers the generation of RANDOM_INTS values which are then sorted and stored as an array.
Good one! I suppose we could do this with an Iterator too but without the cooler limit(xx)