皆さんご存知のとおり、乱数はプログラミング言語の最も基本的な機能の 1 つです。乱数を生成する基本的な方法は同じで、0 と 1 の間の乱数を生成します。単純そうに思えますが、時には興味深い機能を見落としてしまうこともあります。
私たちは本から何を学びますか?
最も明白で直感的な方法は、単純な呼び出しで Java で乱数を生成することです:
java.lang.Math.random()
他のすべての言語では、乱数の生成は、abs、pow、floor、sqrt などの数学ツール クラスを使用するのと同じです。機能。ほとんどの人は、書籍、チュートリアル、コースを通じてこのクラスについて学びます。簡単な例: 倍精度浮動小数点数は 0.0 から 1.0 まで生成できます。次に、上記の情報に基づいて、開発者が 0.0 から 10.0 までの倍精度浮動小数点数を生成したい場合は、次のように書きます:
Math.random() * 10
0 から 10 までの整数を生成するには、次のように書きます。 this:
Math.round(Math.random() * 10)
Advanced
Pass Math.random() のソースコードを読むか、IDE のオートコンプリート機能を利用するだけで、開発者は java.lang.Math.random() が内部でランダムに生成された変数を使用していることを簡単に発見できます。生成されたオブジェクト – 柔軟に使用できる非常に強力なオブジェクト ランダムに生成: ブール値、すべての数値タイプ、さらにはガウス分布。例:
new java.util.Random().nextInt(10)
これには、オブジェクトであるという欠点があります。そのメソッドはインスタンスを通じて呼び出す必要があります。つまり、そのコンストラクターを最初に呼び出す必要があります。十分なメモリがある場合、上記の式は許容されますが、メモリが不足している場合は問題が発生します。
乱数を生成する必要があるたびに新しいインスタンスを作成することを避ける簡単な解決策は、静的クラスを使用することです。 java.lang.Math について考えたことがあると思います。java.lang.Math の初期化が改善されました。このプロジェクトは少量ですが、問題が発生しないことを確認するために、いくつかの簡単な単体テストも行う必要があります。
プログラムが保存用の乱数を生成する必要があると仮定すると、問題が再び発生します。たとえば、状態を保存し、次の乱数を計算するために使用される内部番号であるシードを操作または保護する必要がある場合があります。このような特殊なケースでは、ランダムに生成されたオブジェクトを共有することは不適切です。
同時実行性
Java EE マルチスレッド アプリケーションのコンテキストでは、ランダムに生成されたインスタンス オブジェクトを静的プロパティとしてクラスまたは他の実装クラスに格納できます。幸いなことに、java.util.Random はスレッドセーフであるため、複数のスレッド呼び出しによってシードが破壊されるリスクはありません。
もう 1 つ検討する価値があるのは、マルチスレッドの java.lang.ThreadLocal インスタンスです。遅延アプローチでは、Java 独自の API を介して単一のインスタンスを実装します。もちろん、各スレッドが独自のインスタンス オブジェクトを持つようにすることもできます。
ただし、Java には java.util.Random の単一インスタンスを管理する良い方法がありません。ただし、待望の Java 7 では、乱数を生成する新しい方法が提供されています:
java.util.concurrent.ThreadLocalRandom.current().nextInt(10)
この新しい API は、Math.random() と同様に、単一インスタンス / 静的アクセスという他の 2 つのメソッドの利点を組み合わせています。 ThreadLocalRandom は、高い同時実行性を処理する他のどの方法よりも高速です。
経験
Chris Marasti-Georg は次のように指摘しました:
Math.round(Math.random() * 10)
分布を不均衡にします。たとえば、0.0 ~ 0.499999 は 0 に丸められ、0.5 ~ 1.499999 は 1 に丸められます。では、古い構文を使用して正しいバランスの取れた分散を実現する方法は次のとおりです:
Math.floor(Math.random() * 11)
幸いなことに、java.util.Random または java.util.concurrent.ThreadLocalRandom を使用すれば、上記の問題を心配する必要はありません。 。
Java Practical Project では、java.util.Random API の誤った使用によるいくつかの危険性が紹介されています。このレッスンでは、:
Math.abs(rnd.nextInt())%n
を使用するのではなく、:
rnd.nextInt(n)