Generate a Random Alphanumeric String in Kotlin

1. Overview

In this tutorial, we’ll discuss how to generate a random alphanumeric String in Kotlin using three different approaches: Java Random, Kotlin Random, and Apache Commons Lang RandomStringUtils.

Then, we’ll wrap up with a look at a high-performance approach.

2. Dependencies

Before we dive into the tutorial, let’s add the Apache Commons Lang dependency into our pom.xml:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.8.1</version>
</dependency>

In addition, we can set up some constants for later reference:

const val STRING_LENGTH = 10;
const val ALPHANUMERIC_REGEX = "[a-zA-Z0-9]+";

3. Java Random

First of all, let’s look at how to use Java Random to generate a random String.

In this example, we’ll use ThreadLocalRandom which has a Random instance per thread and safeguards against contention:

private val charPool : List<Char> = ('a'..'z') + ('A'..'Z') + ('0'..'9')

@Test
fun givenAStringLength_whenUsingJava_thenReturnAlphanumericString() {
    val randomString = ThreadLocalRandom.current()
     .ints(STRING_LENGTH.toLong(), 0, charPool.size)
     .asSequence()
     .map(charPool::get)
     .joinToString("")

    assert(randomString.matches(Regex(ALPHANUMERIC_REGEX)));
    assertEquals(STRING_LENGTH, randomString.length);
}

In this example, we’re getting 10 random alphanumeric characters from character pool by generating their indexes, then join them together to create the random String.

ThreadLocalRandom is available since JDK 7We could use java.util.Random instead. But if multiple threads use the same instance of Random, the same seed is shared by multiple threads, causing thread contention.

However, neither ThreadLocalRandom nor Random are cryptographically secure, as it’s possible to guess the next value returned from the generator. Java does provide the noticeably slower java.security.SecureRandom to securely generate a random value.

4. Kotlin Random

From Kotlin 1.3, kotlin.random.Random is available as a multiplatform feature. It uses java.util.Random in JDK 6 and 7, ThreadLocalRandom in JDK 8+ and Math.random in Javascript.

We can get a random String with the same approach:

val randomString = (1..STRING_LENGTH)
  .map { i -> kotlin.random.Random.nextInt(0, charPool.size) }
  .map(charPool::get)
  .joinToString("");

5. Apache Common Lang 

Finally, if we’re still using Kotlin, we can make use of Apache Common Lang libraries to generate a random String:

@Test
fun givenAStringLength_whenUsingApacheCommon_thenReturnAlphanumericString() {
    val randomString = RandomStringUtils.randomAlphanumeric(STRING_LENGTH);

    assert(randomString.matches(Regex(ALPHANUMERIC_REGEX)));
    assertEquals(STRING_LENGTH, randomString.length);
}

In this example, we simply call RandomStringUtils.randomAlphanumeric to get our String with a predefined length.

We should note that RandomStringUtils generate random values by using java.util.Random, which isn’t cryptographically secure as we discussed above. So in case of generating a secured token or value, we can use CryptoRandom in Apache Commons Crypto or Java’s SecureRandom.

We have a tutorial about how to generate a random String in Java as well to cover this topic in more details.

6. Performance

A notable aspect of each of these is that it is calling our random number generator STRING_LENGTH times. If we are creating many Strings or long Strings, these approaches may be too slow. With some extra effort, though, we can simply call for a random sequence of bytes, and then map them to our char pool:

@Test
fun givenAStringLength_whenUsingRandomForBytes_thenReturnAlphanumericString() {
    val random = SecureRandom()
    val bytes = ByteArray(STRING_LENGTH)
    random.nextBytes(bytes)

    val randomString = (0..bytes.size - 1)
      .map { i -> charPool.get((bytes[i] and 0xFF.toByte() and (charPool.size-1).toByte()).toInt())
    }.joinToString("")

    assert(randomString.matches(Regex(ALPHANUMERIC_REGEX)))
    assertEquals(STRING_LENGTH, randomString.length)
}

What makes this approach powerful is that, while we still do STRING_LENGTH lookups to our charPool, we only call on our random generator once. And, aside from being faster, this may also reduce thread contention on shared instances.

Also, note that while bytes[i] and 0xFF.toByte() and charPool.size.toByte() may look advanced, it’s just a way to make sure the random bytes are between and charPool.size().

7. Conclusion

In conclusion, we’ve gone through three approaches to generate a random alphanumeric string in Kotlin, exploring the nuances of each. Then, we shifted gears to examine a high-performance solution that can be repurposed for the Kotlin and Java APIs.

As always, the code can be found over on GitHub.

Leave a Reply

Your email address will not be published.