本系列主要记录分享 SonarLint 扫描出来的Bugs问题修复方案
问题
Bugs描述:Use the original value instead.
问题代码:
Random rand = new Random();
// 这一行是被扫描出来有问题的代码
int randInt = Math.abs(rand.nextInt());
解决办法
Random rand = new Random();
int randInt = Math.abs(rand.nextInt(Integer.MAX_VALUE));
问题分析
SonarLint 扫描结果的大概意思:代码里 Math.abs()
取绝对值后的结果,仍可能是一个负数,所以建议:
- 使用
Random.nextLong()
去获取目标结果值; - 直接去掉
Math.abs()
的使用,直接取rand.nextInt()
的值。
是不是在想为什么 Math.abs()
取到的值仍可能是一个负数呢?
这里演示一种场景:
@Test
public void testDemo1() {
Integer i = Math.abs(Integer.MIN_VALUE);
System.out.println(i);
}
结果展示:
我们都知道 Integer 的取值范围:-2147483648 ~ 2147483647,所以当我们对 Integer.MIN_VALUE
去绝对值(Math.abs()
)操作后,得到 2147483648 就超出了 int类型的取值范围。
在Oracle docs: Integer Operations中有这么一段话:
The integer operators do not indicate overflow or underflow in any way.
整数的操作不会告诉我们向上溢出还是向下溢出。
——Oracle docs
所以,溢出的结果已由语言指定,独立于JVM版本:
Integer.MAX_VALUE
+ 1 ==Integer.MIN_VALUE
Integer.MIN_VALUE
- 1 ==Integer. MAX_VALUE
其他整数类型也是如此。
所以 SonarLint 才会提示我们的代码最终目标是想获取一个正值的数,当前 Math.abs(rand.nextInt())
写法获取的结果不一定是正数。
我之前写过一篇关于:Java 边界陷阱(边界值的校验) 的博客,大家有兴趣可以瞅瞅~
我这里的解决办法是,Random 取值时指定 n 的取值范围,这样取值就不会取出负数,
ps:Random.nextInt(int n),给定一个参数n,nextInt(n)将返回一个大于等于0小于n的随机数,即:0 <= nextInt(n) < n。
参考
Sonar检测Math.abs(new Random().nextInt()) “Use the original value instead”