I think your first requirement (not saving every promotional code in a database) is problematic.
The question is, is it allowed to redeem a single promotional code multiple times?
If this is not allowed then you have to store the already redeemed codes in some persistent data store anyway, so why not store the generated codes in the persistent data store from the beginning, together with a flag indicating whether it has been redeemed or not?
If you don't want to store all codes / can't store all codes, you could still use a Random
with a seed unique to your current campaign:
long seed = 20190921065347L; // identifies your current campaign
Random r = new Random(seed);
for (int i = 0; i < numCodes; i++) {
System.out.println(r.nextLong());
}
or
long seed = 20190921065347L; // identifies your current campaign
Random r = new Random(seed);
r.longs(numCodes, 100_000_000_000_000L, 1_000_000_000_000_000L)
.forEach(System.out::println);
To find out whether a code is valid you can generate the same codes again:
long seed = 20190921065347L; // identifies your current campaign
Random r = new Random(seed);
System.out.println(
r.longs(numCodes, 100_000_000_000_000L, 1_000_000_000_000_000L)
.anyMatch(l -> l == 350160558695557L));