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.12.0</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 the 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 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 detail.

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[random.nextInt(charPool.size)]
    }.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.

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.

4 Comments
Oldest
Newest
Inline Feedbacks
View all comments
Felix
Felix
7 months ago

Kotlin Collections has a random function which can be used like this

(1..length)
    .map { charPool.random() }
    .joinToString("")
Loredana Crusoveanu
Loredana Crusoveanu
4 months ago
Reply to  Felix

Thanks for the suggestion. We’ll update the article.

Tomasz Kiljańczyk
Tomasz Kiljańczyk
7 months ago

I think that code in point 6 could be simplified. Correct me if I’m wrong, but bytes variable is used only to invoke .map and create n-elements list. You could replace it with this code and it should have same effect.

@Test
fun givenAStringLength_whenUsingRandomForBytes_thenReturnAlphanumericString() {
    val random = SecureRandom()

    // List class can be used too
    val randomString = Array(STRING_LENGTH) {
        charPool[random.nextInt(charPool.size)]
    }.joinToString("")

    assert(randomString.matches(Regex(ALPHANUMERIC_REGEX)))
    assertEquals(STRING_LENGTH, randomString.length)
}
Loredana Crusoveanu
Loredana Crusoveanu
4 months ago

Thanks, Tomasz. We’ll update the example.

Comments are closed on this article!