-
Notifications
You must be signed in to change notification settings - Fork 0
RandomStream
The RandomStream utils library contains two ways of getting random strings.
On one hand you can use the prebuild String method Random.String.build() and on the other hand you can use the Random.build() methods for a custom type T.
| > NOTE: You can use the unit test as small examples. See here. |
|---|
The inner class Random.String contains a build method which returns a Random.RandomStream<String> object which itself
contains a lot of methods you can invoke.
This builder uses the generator Generator.alphanumeric().
Now let's get started:
Random.String.build()
.stream(13, 8) // returns java.util.stream.Stream<String>
.forEach(System.out::println);will generate a stream with 8 strings with the length of 13 characters and print it:
lIt1EV8C13gc8
eaXKugM3o3cuv
G4Vd8PABotdQc
c3NwTvtFsz6c2
hNV1K02hLeGOI
tD4AvdTD3N0FP
1ZxVQhWAbH7ch
hxQ5b5iz07mXm
If you want the filter the generated strings for some reason you could do this using the .filter() method of the Stream<T> class,
but it will result in the wrong number of strings.
This happens because stream(length, count) generate count (in the examples 8) strings which then will be filtered and therefor reduced.
The get rid of this behaviour you can add a filter as the third parameter so the stream() method will generate the correct number of strings:
Random.String.build()
.stream(13, 8, s -> s.startsWith("a"))
.forEach(System.out::println);axLUsnnjwKDAt
aDDppFvhnmbsY
ap2oVDbO3I2pE
aC6lpX1NhQgvv
acRbQJIJIMBel
aVjaMs3wcNB3G
aPkgufKLxizvJ
aGvF3Gn5yybz7
You may notice that this is not very efficient.
This insufficient behavior is based on implementation of the stream(length, count, filter) method:
It generates random strings with the given length, filter this strings and stops when count strings were generated.
Let's take a deeper look to the example form above: As already said, Random.String.build() uses the Generator.alphanumeric()
generator, which generates strings using the chars A-Z,a-z,0-9.
Assuming that the generators output is equal distributed the probability of getting an a is 1/(26+26+10) = 1/62.
So when you want count strings it will generate count*62 strings internally which results in this inefficiency.
Be careful when you use the filter parameter and consider using a custom generator
There are three more stream methods with an equal structure.
-
parallelStream()will do the same asstream()in a parallel way. Be aware that the parallel execution is not always faster then the sequential execution. -
uniqueStream()will ensure that you won't get duplicates. -
parallelUniqueStream()will ensure that you won't get duplicates in a parallel way.
list() will generate you a List<String>.
Using the common static method <T>stream(final Generator.ICharPool<T> pool)) you are able to generate random string of
each type T but therefore you need a matching generator.
This library ships with a String and BigInteger generator (see more on custom generators.
So you are able to build your custom stream using a generator and a char pool:
Random.build(new RandomNumberGenerator("89"::toCharArray))where "89" are the used characters (this generator will produce strings of eights and nines).
You can also see that the ICharPool interface can be easily used as lambda or in this case as method reference.
So the code above is just syntax sugar for:
final Generator.ICharPool charPool = "89"::toCharArray;
Random.build(new RandomNumberGenerator(charPool))
// ----- OR -------
final Generator.ICharPool charPool = () -> "89".toCharArray();
Random.build(new RandomNumberGenerator(charPool))
// ----- OR -------
final Generator.ICharPool charPool = new Generator.ICharPool() {
@Override
public char[] getCharacters() {
return "89".toCharArray();
}
};
Random.build(new RandomNumberGenerator(charPool))This will produce a class Random.RandomStream<BigInteger>and was already used in the paragraph above, therefor you can use stream(), parallelStream(),uniqueStream() and parallelUniqueStream():
Random
.build("89"::toCharArray)
.stream(5, 8)
.forEach(System.out::println);99989
88988
89988
99989
88988
98888
99888
89988
Passing a custom java.util.Random object as the second parameter will customize the 'randomness' (if the generator support it):
Random
.build(new RandomStringGenerator("89"::toCharArray, new SecureRandom()))
.stream(5, 8)
.forEach(System.out::println);The generation of the strings happens char-wise and is executed by a so called generator which take a char pool as an input.
So each generator implements the IRandomStringGenerator<T> interface where T is the result type of the generation.
So for example the RandomStringGenerator implements IRandomStringGenerator<String>.
| Name | type T
|
CharPool | Example |
|---|---|---|---|
| Generator.alphanumeric() | String |
A-Z,a-z,0-9 |
hJswp |
| Generator.numbers() | String |
0-9 |
46417 |
| Generator.integerNumbers() | BigInteger |
0-9 |
74132 |
| Generator.alphanumericSigns() | String |
A-Z,a-z,0-9,!§$%&/()=?{[]}\-_.,:;+*~#<> |
k6&/x |
| Generator.unicode() | String |
Unicode | గ?⬺楟? |
Attention: The unicode generator may contain errors as it doesn't respect some unicode restrictions (e.g. currently not used areas).
As already said simple implement the interface IRandomStringGenerator<T>.
It is a good idea to separate the char pool and the generator itself by using a appropriate constructor and the Generator.ICharPool interface.
You can also use the generator with the lambda syntax and reuse the preshipped generators:
Random
.build(length -> "aa" + Generator.alphanumeric().next(length - 4) + "aa")
.stream(13, 8)
.forEach(System.out::println);
//aajsaNCWYGBaa
//aaYrIEnypXMaa
//aagsDLR633taa
//aaMrVtwqPZjaa
//aaLAQGbbaqkaa
//aaO5U0frxtgaa
//aaZP94oQSRDaa
//aazStPYtfKcaa