代码改变世界

[hyddd的FindBugs分析记录][H B BC] Random object created and used only once

2009-02-16 16:45  hyddd  阅读(8662)  评论(1编辑  收藏

[H B BC] Random object created and used only once [DMI_RANDOM_USED_ONLY_ONCE]

This code creates a java.util.Random object, uses it to generate one random number, and then discards the Random object. This produces mediocre quality random numbers and is inefficient. If possible, rewrite the code so that the Random object is created once and saved, and each time a new random number is required invoke a method on the existing Random object to obtain it.

If it is important that the generated Random numbers not be guessable, you must not create a new Random for each random number; the values are too easily guessable. You should strongly consider using a java.security.SecureRandom instead (and avoid allocating a new SecureRandom for each random number needed).

 

先看看下面这段FindBugs认为有问题的代码:

public int getRandom(int seed) {
    
return new Random(seed).nextInt();
}

看BUG解释,FindBugs建议是:

1.new一个Random的对象,保存之,然后每次都使用这个对象去获取随机数,而不要每次new一个Random对象去获取。

2.FindBugs强烈推荐使用java.security.SecureRandom代替Random。

根据以上要求,我修改了我的代码:

public class Test  extends Thread{
    
private SecureRandom ran;

    Test(
int seed){
        ran 
= new SecureRandom();
    }
    
    
public int getRandom(int seed) {
        
return ran.nextInt();
    }
}

至于为什么FindBugs要这样建议,它这里没有说,我也不太确定,但我的这样猜测的:

1.现在所谓的随机函数Random都是伪随机,不是真正意义上的随机,他们都是使用一个初始值(比如:当前时间),然后把初始值放入随机算法生成随机数。

2.如果每次都new Random()可能会影响随机性,这个可以看看下面代码:

 

System.out.println(new Date().getTime());
System.out.println(
new Random(new Date().getTime()).nextInt());
System.out.println(
new Date().getTime());
System.out.println(
new Random(new Date().getTime()).nextInt());
System.out.println(
new Random(new Date().getTime()).nextInt());
System.out.println(
new Random(new Date().getTime()).nextInt());
System.out.println(
new Random(new Date().getTime()).nextInt());
System.out.println(
new Random(new Date().getTime()).nextInt());
System.out.println(
new Random(new Date().getTime()).nextInt());
System.out.println(
new Random(new Date().getTime()).nextInt());
System.out.println(
new Random(new Date().getTime()).nextInt());
System.out.println(
new Random(new Date().getTime()).nextInt());

输出的结果是:

 

1235021925734
779046670
1235021925734
779046670
779046670
779046670
779046670
779046670
779046670
779046670
779046670
779046670
为什么会这样??其实就是因为在很短的时间内,两次getTime()的值是相等的,而Random有是伪随机的,如果每次都new一个Random然后获取其随机数。从结果可以看出风险了。这样有可能每次获得的随机数值都是相同的。

3.每次都生成对象肯定比每次都使用同一个对象的效率要低。

4.SecureRandom可能是对Random在随机算法上做了改进,使之更安全。(还没看源代码,这个也仅仅是我的猜测而已)