Java中的随机数

在Java中,我们不免需要生成随机数,而且可能需要生成在某个范围内的随机数。今天在公司就有一个需求是:在一个List<Integer>的list中,随机选取5%的随机数出来。和我的导师商讨之后,确定了一种方案,希望和大家分享。如果大家有更好的解决方案,请给小编评论哦。

在Java中,大家可以很容易想到的实现随机数的方法可以采用Random()方法或Math.Random()方法。

使用Random()函数,构造函数有两个:Random()和Random(long seed)。一个是以当前时间为默认种子,一个是以指定的种子进行随机。使用Math.Random()方法可以产生一个[0.0,1.0)区间的double类型的随机值,根据需要的随机数的范围,乘以对应的数字后,再强制类型转换为int类型即可得到随机数。

第三种方法可以通过取得当前系统的毫秒数,对所需要的范围进行取模运算,得到随机值。

上述三种方法对于单个的随机数都可以实现。但是我需要生成指定个数的随机数列,可能使用循环的效率就没有看起来那么高了。如果在若干次的随机数中,运气很不好,产生的随机数命中了同一个数字,难么就白白浪费掉了多次CPU资源。

比如在上面所说的场景,我现在有一个List<Integer>类型的list,其中有5000条数据,我需要随机选出其中的5%的数字,即250条数据,其实就是选出250个下标。容易想到的方法是通过while循环、for循环或者do{}while循环,每次使用Random()或者Math.Random()产生一个随机数,如果这个随机数没有产生过,则选择,否则进行下一次循环。

上述方法存在一个问题:如果在多次循环的过程中,都产生了一个随机数,那么循环的次数就势必远远多余250次。那么有没有方法可以在有限次的循环内完成呢?

使用java.util.Collection#shuffle()函数,该函数的作用是对集合进行重新打乱(随机排序)。jdk源码如下,其实本质是利用了swap较好函数对list元素进行打乱。最后取得list数组中的前n个元素,实现随机数队列的效果。该方法可以在有限次循环中完成元素的打乱,是取得随机数队列的一种思路。

    public static void shuffle(List<?> list, Random rnd) {
        int size = list.size();
        if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {
            for (int i=size; i>1; i--)
                swap(list, i-1, rnd.nextInt(i));
        } else {
            Object arr[] = list.toArray();

            // Shuffle array
            for (int i=size; i>1; i--)
                swap(arr, i-1, rnd.nextInt(i));

            // Dump array back into list
            // instead of using a raw type here, it's possible to capture
            // the wildcard but it will require a call to a supplementary
            // private method
            ListIterator it = list.listIterator();
            for (int i=0; i<arr.length; i++) {
                it.next();
                it.set(arr[i]);
            }
        }
    }

 

<think>好的,我现在需要回答用户关于如何在Java中生成随机数的问题。根据用户提供的引用内容,我需要整理出不同的方法并解释它们的实现方式。首先,用户提到了java.util.Random类和Math.random()方法,这两个是基本的方法。然后还有Java 7引入的ThreadLocalRandom,以及可能的区间随机数的生成。 首先,我应该按照时间顺序或者常用程度来组织这些方法。可能从最基础的开始,比如Math.random(),因为它简单,但功能有限。接着介绍Random类,详细说明如何创建实例和使用nextInt等方法。然后,提到Random类的线程安全问题,进而引出Java 7的ThreadLocalRandom,解释它的优势和使用方式。 接下来需要考虑生成指定区间的随机数,比如如何生成0到某个数之间的随机数,或者一个闭区间的随机数,比如[min, max]。这里可能需要数学公式,比如nextInt(max - min + 1) + min。需要确保这里的公式用LaTeX格式,比如$[0, n)$和$[min, max]$。 另外,用户提供的引用中提到不带参数的Random构造函数产生的随机数不会重复,但某些情况下可能重复。需要澄清这一点,实际上随机数生成器是伪随机的,种子相同的话序列会重复,所以如果使用相同种子可能会得到重复的序列,但一般情况下不带参数的构造函数使用系统时间作为种子,所以不同的实例会产生不同的序列。 在代码示例方面,需要给出不同方法的代码片段,比如使用Math.random()生成0-100的整数,使用Random类生成区间数,以及ThreadLocalRandom的例子。要确保代码语法正确,比如在Java中正确调用方法。 可能还需要提到线程安全的问题,比如在多线程环境下使用Random可能导致性能问题,因此推荐使用ThreadLocalRandom来提高并发性能。同时,注意每个方法的优缺点,比如Math.random()返回的是double类型,需要转换才能得到整数,而Random类更灵活。 最后,生成相关问题,可能涉及性能比较、种子设置的影响、随机数的应用场景等。需要确保问题相关且有价值,帮助用户进一步学习。 现在,需要检查是否符合用户的要求:结构清晰,分步骤解释,使用正确的LaTeX格式,引用标记正确,代码块正确,以及生成相关问题。同时要使用中文回答,避免使用Markdown格式,除了代码块需要用三个反引号包裹。</think>### Java生成随机数的方法及实现方式 #### 1. **Math.random() 方法** - **功能**:生成$[0, 1)$范围内的`double`类型伪随机数。 - **实现**: ```java double random = Math.random(); // 生成0.0 ≤ random < 1.0 int num = (int)(Math.random() * 100); // 生成0-99的整数 ``` - **特点**:简单易用,但功能有限,适用于简单场景[^1]。 #### 2. **java.util.Random 类** - **功能**:支持多种数据类型(整数、浮点数、布尔值等)的随机数生成。 - **实现**: ```java Random rd = new Random(); int num1 = rd.nextInt(); // 任意整数 int num2 = rd.nextInt(100); // 生成0-99的整数 double num3 = rd.nextDouble(); // 生成0.0 ≤ num3 < 1.0 ``` - **区间随机数**:生成$[min, max]$范围的整数: ```java int min = 10, max = 20; int num = rd.nextInt(max - min + 1) + min; // 10 ≤ num ≤ 20 ``` - **注意**:默认构造函数以系统时间为种子,不同实例生成不同序列[^3]。 #### 3. **ThreadLocalRandom(Java 7+)** - **功能**:针对多线程优化的高性能随机数生成器。 - **实现**: ```java int num = ThreadLocalRandom.current().nextInt(1, 100); // 生成1-99的整数 ``` - **特点**:避免多线程竞争,性能优于`Random`[^2]。 #### 4. **SecureRandom 类** - **功能**:生成高安全性的随机数(如加密场景)。 - **实现**: ```java SecureRandom sr = new SecureRandom(); int secureNum = sr.nextInt(); ``` ### 代码示例对比 | 方法 | 代码示例 | 适用场景 | |--------------------|-------------------------------------------|------------------| | `Math.random()` | `(int)(Math.random() * 100)` | 简单单线程需求 | | `Random` | `new Random().nextInt(100)` | 通用随机需求 | | `ThreadLocalRandom`| `ThreadLocalRandom.current().nextInt(1,5)`| 高并发多线程场景 |
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值