目录
2、java.util.Random.ints(Java 8)
小问题大学问
最近看到一个简单的编程题,描述如下:
创建一个长度为8的int型数组,要求取值为1-30,同时元素值各不相同。
当时心中对题大致描述了编程思路,
1、给arr[i]赋值 2、如果arr[i]已经与前面重复,则重新给arr[i]赋值,直到不重复为止 3、否则继续给arr[i++]赋值
代码如下:
public class ArrayExercise {
public static int[] method1(int arrLength, int rMax) {
int[] arr = new int[arrLength];
for (int i = 0; i < arr.length; i++) {
arr[i] = new Random().nextInt(rMax) + 1;
boolean flag = false;
while (true) {
for (int j = 0; j < i; j++) {
if (arr[i] == arr[j]) {
flag = true;
break;
}
}
if (flag) {
arr[i] = (int) (Math.random() * rMax) + 1;
flag = false;
continue;
}
break;
}
}
return arr;
}
}
使用单元测试,对此函数执行,为了方便查看结果,特意将数组排序,调用方法如下:
public class MainTest {
@Test
public void test1(){
// 创建一个长度为8的int型数组,要求取值为1-30,同时元素值各不相同
int[] ints2 = ArrayExercise.method2(8, 30);
Arrays.sort(ints2);
System.out.print("arr2: ");
for (int anInt : ints2) {
System.out.print(anInt + ", ");
}
}
执行结果如下:
执行结果与思路没有问题,但是此题答案给了一个很简洁的代码,是值得我们借鉴和思考的,答案如下:
读者可能会注意到,我在上述代码中,对随机数的生成,使用了两种不同的方式,由此,引出了该文需要讨论的一个小知识点,Java随机数的生成。
Java随机数
1、java.util.Random.nextInt
此Random().nextInt(int bound)生成一个从[0,bound)的随机整数。
- int anInt1 = new Random().nextInt(31); // [0,31), 即[0,30]
- int anInt2 = new Random().nextInt(30) + 1; // [1.31),即[1,30]
2、java.util.Random.ints(Java 8)
此Random.ints(int randomNumberOrigin, int randomNumberBound)或Random.ints(int min, int max)生成一个[min,max)的随机整数。但是此方法返回的是一个IntStream。源码如下:
public IntStream ints(int randomNumberOrigin, int randomNumberBound) {
if (randomNumberOrigin >= randomNumberBound)
throw new IllegalArgumentException(BadRange);
return StreamSupport.intStream
(new RandomIntsSpliterator
(this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
false);
}
所以需要调用findFirst()返回一个整数流的第一个元素,如:
int rNumber = random.ints(1, 31).findFirst().getAsInt(); //[1,31),即[1,30]
3、java.lang.Math.random()
此Math.random()给出从[0.0,1.0),使用方法如下:
(int) (Math.random() * 30) + 1; // [1,31),即[1,30]
(int)(Math.random() * ((30 - 5) + 1)) + 5; //[5,30]
(int)(Math.random() * ((max - min) + 1)) + min //[min,max]
备注:
网上说,nextInt生成的随机数效率高于Math.random(),时间上前者大约是后者50%到80%的时间。
翻看源码,发现Math.random()是Random.nextDouble()的一个内部方法,而Random.nextDouble()使用了Random.next()两次。
public static double random() {
return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble();
}public double nextDouble() {
return (((long)(next(26)) << 27) + next(27)) * DOUBLE_UNIT;
}
路漫漫其修远兮,吾将上下而求索。 ---屈原