1概要

このチュートリアルでは、3つの異なるアプローチ(Java

Random

、Kotlin

Random

、およびApache Commons Lang

RandomStringUtils

)を使用して、Kotlinでランダムな英数字

String

を生成する方法について説明します。

それでは、高性能のアプローチを見ていきましょう。


2依存関係

チュートリアルを始める前に、https://search.maven.org/search?q=g:org.apache.commons%20AND%20a:commons-lang3[Apache Commons Lang依存関係]を

pom.xmlに追加しましょう。 :

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

さらに、後で参照できるように定数を設定することもできます。

const val STRING__LENGTH = 10;
const val ALPHANUMERIC__REGEX = "[a-zA-Z0-9]+";


3 Java

Random


まず最初に、Javaの

Random

を使用してランダムな

String




__.

__を生成する方法を見てみましょう。

この例では、スレッドごとに

Random

インスタンスを持ち、競合から保護する

ThreadLocalRandom

を使用します。

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);
}

この例では、


インデックスを生成して文字プールから10個のランダムな英数字を取得し、


それらを結合してランダムな__Stringを作成します。


ThreadLocalRandom

はJDK 7

__以降で利用可能です。


代わりに

java.util.Random

を使用できます。ただし、複数のスレッドが同じ

Random__のインスタンスを使用すると、同じシードが複数のスレッドで共有され、スレッドの競合が発生します。

ただし、

ThreadLocalRandom



Random

も暗号的に安全ではありません。これは、ジェネレータから返される次の値を推測することが可能なためです。 Javaは乱数を安全に生成するために著しく遅い

java.security.SecureRandom

を提供します。


4コトリン

Random


Kotlin 1.3から、

kotlin.random.Random

がマルチプラットフォーム機能として利用可能になりました。 JDK 6と7では

java.util.Random

、JDK 8では

ThreadLocalRandom

、Javascriptでは

Math.random

を使用します。

同じ方法でランダムな

String

を取得できます。

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


5 Apache Common Lang

最後に、まだKotlinを使用している場合は、Apache Common Langライブラリを使用してランダムな

String



____を生成できます。

@Test
fun givenAStringLength__whenUsingApacheCommon__thenReturnAlphanumericString() {
    val randomString = RandomStringUtils.randomAlphanumeric(STRING__LENGTH);

    assert(randomString.matches(Regex(ALPHANUMERIC__REGEX)));
    assertEquals(STRING__LENGTH, randomString.length);
}

この例では、

RandomStringUtils.randomAlphanumeric

を呼び出して、事前定義された長さの

String

を取得します。


RandomStringUtils



java.util.Random

を使用してランダムな値を生成しますが、これは前述したように暗号的に安全ではありません。 ** 安全なトークンまたは値を生成する場合は、Apache Commons Cryptoの

CryptoRandom

またはJavaの__SecureRandomを使用できます。


Javaでランダムな

String

を生成する方法

についてのチュートリアルもあります。また、このトピックについて詳しく説明します。


6. パフォーマンス

これらのそれぞれの注目すべき点は、乱数ジェネレータを

__STRING

LENGTH

__timesと呼んでいることです。たくさんの

文字列または長い__文字列を作成している場合、これらのアプローチは遅すぎるかもしれません。


追加の労力を払って

では、単純にランダムなバイトシーケンスを呼び出してから、それらをcharプールにマッピングできます。

@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)
}

このアプローチを強力にしているのは、**

STRING

LENGTH

の検索を

charPool__に対して行っている間は、ランダムジェネレータを1回だけ呼び出すだけです。

また、

bytes[i]と0xFF.toByte()およびcharPool.size.toByte()

は高度に見えるかもしれませんが、ランダムバイトが

__0




charPool.size()__の間にあることを確認するための単なる方法です。


7. 結論

結論として、Kotlinでランダムな英数字の文字列を生成するための3つのアプローチを経て、それぞれのニュアンスを調べました。それから、KotlinとJava APIのために再利用できる高性能なソリューションを検討するためにギアをシフトしました。

いつものように、コードはhttps://github.com/eugenp/tutorials/tree/master/core-kotlin[GitHubに載って]を見つけることができます。