كيفية توليد رقم عشوائي في Java
⚡ ملخص ذكي
أرقام عشوائية في Java تأتي من أربعة خيارات مكتبة قياسية ذات صلة، وهي فئة Random و Math.random و ThreadLocalRandom و SecureRandom، كل منها يغطي مزيجًا مختلفًا من السرعة وأمان الخيوط والقوة التشفيرية للتطبيقات الحقيقية.

تظهر الأرقام العشوائية في كل مكان في Javaبدءًا من بيانات اختبار الوحدات وألعاب رمي النرد وصولًا إلى رموز الجلسات ومجموعات الأوراق المختلطة. يشرح هذا البرنامج التعليمي كيفية توليد أرقام عشوائية في Java استخدام كل خيار في المكتبة القياسية وكيفية اختيار الخيار المناسب للمهمة.
إنشاء رقم عشوائي في Java
استخدم Java توفر المكتبة القياسية أربع طرق شائعة لتوليد رقم عشوائي:
java.util.Randomهي فئة عامة الأغراض. تُنتج قيمًا منطقية، وأعدادًا صحيحة، وأعدادًا طويلة، وأعدادًا عشرية، وأعدادًا مزدوجة من خلال طرق مثلnextInt,nextLongوnextDouble.Math.randomهي دالة مساعدة ثابتة تُرجع قيمة عددية مزدوجة بين 0.0 (شاملة) و1.0 (غير شاملة) باستخدام مُعامل مشتركRandomداخليا.ThreadLocalRandominjava.util.concurrentيمنح كل خيط مولده الخاص، لذلك لا تتنافس الخيوط المتعددة على مثيل واحد.SecureRandominjava.securityينتج أرقامًا شبه عشوائية قوية من الناحية التشفيرية لكلمات المرور ومعرفات الجلسات والمفاتيح.
توضح الأقسام التالية كيفية توليد عشرة أرقام عشوائية باستخدام كل طريقة.
مثال: إنشاء رقم عشوائي باستخدام Java فئة عشوائية
يستخدم المثال الأول java.util.Random لإنتاج عشرة أعداد صحيحة في النطاق من 0 إلى 99 شاملةً:
import java.util.Random; public class RandomNumbers { public static void main(String[] args) { Random objGenerator = new Random(); for (int iCount = 0; iCount < 10; iCount++) { int randomNumber = objGenerator.nextInt(100); System.out.println("Random No : " + randomNumber); } } }
الإخراج:
Random No : 17 Random No : 57 Random No : 73 Random No : 48 Random No : 68 Random No : 86 Random No : 34 Random No : 97 Random No : 73 Random No : 18
مثال على Random يتم إنشاؤها كـ objGenerator. nextInt(int bound) تُرجع هذه الطريقة قيمة بين 0 (شاملة) والحد المُحدد (غير شامل)، لذا nextInt(100) تُنتج قيمًا من 0 إلى 99. ولجعل التسلسل قابلاً للتكرار، مرر قيمة ابتدائية إلى الدالة البانية، على سبيل المثال new Random(42); نفس البذرة تنتج دائمًا نفس التسلسل، وهو أمر مفيد في الاختبارات والمحاكاة.
مثال: الاستخدام Java Math.random
لتوليد عشر قيم عشوائية في النطاق من 0.0 إلى 1.0، استدعِ الدالة الثابتة Math.random طريقة داخل حلقةهذه هي أسرع طريقة للحصول على عدد عشري عشوائي دون إنشاء كائن مولد:
public class DemoRandom { public static void main(String[] args) { for (int xCount = 0; xCount < 10; xCount++) { System.out.println(Math.random()); } } }
الإخراج:
0.46518450373334297 0.14859851177803485 0.5628391820492477 0.6323378498048606 0.1740198445692248 0.9140544122258946 0.9167350036262347 0.49251219841030147 0.7426056725722353 0.2039418871298877
تحت غطاء محرك السيارة، Math.random يُنشئ ثابتًا واحدًا Random عند الاستخدام الأول والمكالمات nextDouble هذا المولد المشترك الوحيد مناسب للعروض التوضيحية، ولكنه يصبح عنق زجاجة تحت ضغط الحمل المتعدد الخيوط الثقيل، وهو ما تتناوله الأقسام التالية.
توليد رقم عشوائي ضمن نطاق مخصص
تحتاج البرامج الحقيقية عادةً إلى قيمة عشوائية ضمن نطاق محدد، مثل عدد صحيح بين 1 و6 لرمي النرد، أو عدد عشري بين 10.0 و20.0 للمحاكاة. ويغطي نمطان جميع الحالات تقريبًا.
عدد صحيح عشوائي بين الحد الأدنى والحد الأقصى (شاملًا):
import java.util.Random; public class RangeDemo { public static void main(String[] args) { Random rnd = new Random(); int min = 1; int max = 6; // nextInt(max - min + 1) returns 0..(max-min), then shift by min int dice = rnd.nextInt(max - min + 1) + min; System.out.println("Dice roll : " + dice); } }
عدد عشوائي مضاعف بين الحد الأدنى والحد الأقصى:
double min = 10.0; double max = 20.0; double value = min + (max - min) * Math.random(); System.out.println("Value : " + value);
يعمل كلا النمطين عن طريق أخذ قيمة من النطاق الأصلي للمولد، وتوسيع نطاقها ليتناسب مع عرض النطاق المستهدف، ثم إزاحتها لأعلى بالحد الأدنى. إذا كنت على Java في الإصدار 8 أو أحدث، تتوفر نفس النتيجة من خلال الإصدار الأحدث ints, longsو doubles طرق البث على Random، على سبيل المثال rnd.ints(10, 1, 7).forEach(System.out::println) لعشر رميات نرد.
ThreadLocalRandom للمعالجة متعددة الخيوط Code
مشترك واحد Random هو آمن للاستخدام المتزامن ولكنه بطيء في ظل التنافس لأن كل خيط يجب أن يتزامن على نفس البذرة الداخلية. ThreadLocalRandom، أضيفت في Java 7 ويعيش في java.util.concurrent، مما يمنح كل خيط مولده الخاص، وبالتالي لا يوجد تنازع على القفل.
import java.util.concurrent.ThreadLocalRandom; public class ThreadLocalDemo { public static void main(String[] args) { // random int in [1, 100] int i = ThreadLocalRandom.current().nextInt(1, 101); // random long in [1000, 5000] long l = ThreadLocalRandom.current().nextLong(1000L, 5001L); // random double in [0.0, 1.0) double d = ThreadLocalRandom.current().nextDouble(); System.out.println(i + " " + l + " " + d); } }
استعمل ThreadLocalRandom.current() داخل سلاسل العمل، والتدفقات المتوازية، وأي مهمة متزامنة. لاحظ أن setSeed يلقي UnsupportedOperationExceptionلذا، فإنّ عملية البذر من أجل التكرار غير مدعومة؛ إذا كنت بحاجة إلى بذرة ثابتة، فالتزم بالبذرة العادية. Random.
SecureRandom للتوليد العشوائي الحساس أمنياً Numbers
حالات Random و ThreadLocalRandom ليست آمنة تشفيرياً. فبمجرد الحصول على بضع عينات من المخرجات، يستطيع المهاجم إعادة بناء الحالة الداخلية والتنبؤ بالقيم المستقبلية. بالنسبة لكلمات المرور، ورموز الجلسة، وقيم الملح، ومفاتيح التشفير، استخدم java.security.SecureRandom بدلاً من ذلك، يستمد مواده الأولية من مخزون الإنتروبيا لنظام التشغيل وينتج قيماً يصعب التنبؤ بها.
import java.security.SecureRandom; public class SecureDemo { public static void main(String[] args) { SecureRandom secure = new SecureRandom(); byte[] token = new byte[16]; secure.nextBytes(token); // 128-bit random token int otp = secure.nextInt(1_000_000); // 6-digit one-time code System.out.println("OTP : " + String.format("%06d", otp)); } }
SecureRandom أبطأ من Random لأنه يستخدم خوارزميات أقوى ومواد أولية أكثر ثراءً. خصصه لأعمال الأمن واستخدم المولدات الأسرع للألعاب والمحاكاة وبيانات الاختبار.
