Java常用工具类

JDK 自带

Math

顾名思义,Math类就是用来进行数学计算的,它提供了大量的静态方法来便于我们实现数学计算:

求绝对值:

1
2
Math.abs(-1); // 1
Math.abs(-2.2); // 2.2

取最大或最小值:

1
2
Math.max(100, 101); // 101
Math.min(1.2, 3.1); // 1.2

计算x^y次方:

1
Math.pow(2, 10); // 1024

计算√x:

1
Math.sqrt(2); // 1.4142135623730951

计算指数与对数:

1
2
3
Math.exp(2); // 7.38905609893065
Math.log(2); // 以 e 为底的对数 0.6931471805599453
Math.log10(2); // 以 10 为底的对数 0.3010299956639812

三角函数:

1
2
3
4
5
Math.sin(3.14); // 0.00159...
Math.cos(3.14); // -0.9999...
Math.tan(3.14); // -0.0015...
Math.asin(1.0); // 1.57079...
Math.acos(1.0); // 0.0

Math还提供了几个数学常量:

1
2
double pi = Math.PI; // 3.14159...
double e = Math.E; // 2.7182818...

生成一个随机数x,x的范围是0 <= x < 1

1
Math.random(); // 0.53907... 每次都不一样

Java 标准库还提供了一个 StrictMath,它提供了和 Math 几乎一模一样的方法。这两个类的区别在于,由于浮点数计算存在误差,不同的平台(例如x86和ARM)计算的结果可能不一致(指误差不同),因此,StrictMath 保证所有平台计算结果都是完全相同的,而 Math 会尽量针对平台优化计算速度,所以,绝大多数情况下,使用 Math 就足够了。

Random

Random用来创建伪随机数。所谓伪随机数,是指只要给定一个初始的种子,产生的随机数序列是完全一样的。

要生成一个随机数,可以使用nextInt()nextLong()nextFloat()nextDouble()

1
2
3
4
5
6
Random r = new Random();
r.nextInt(); // 245439114,每次都不一样
r.nextInt(10); // 9,生成一个[0,10)之间的int
r.nextLong(); // -485876652878521410,每次都不一样
r.nextFloat(); // 0.6454043,生成一个[0,1)之间的float
r.nextDouble(); // 0.44460046556701727,生成一个[0,1)之间的double

创建 Random实例时,如果不给定种子,就使用系统当前时间戳作为种子,因此每次运行时,种子不同,得到的伪随机数序列就不同。如果我们在创建 Random 实例时指定一个种子,就会得到完全确定的随机数序列:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Random r = new Random(12345);
for (int i = 0; i < 10; i++) {
System.out.println(r.nextInt(100));
}
// 51
// 80
// 41
// 28
// 55
// 84
// 75
// 2
// 1
// 89

有伪随机数,就有真随机数。实际上真正的真随机数只能通过量子力学原理来获取,而我们想要的是一个不可预测的安全的随机数,SecureRandom就是用来创建安全的随机数的:

1
2
SecureRandom sr = new SecureRandom();
System.out.println(sr.nextInt(100));

SecureRandom 无法指定种子,它使用RNG(random number generator)算法。JDK的 SecureRandom 实际上有多种不同的底层实现,有的使用安全随机种子加上伪随机数算法来产生安全的随机数,有的使用真正的随机数生成器。实际使用的时候,可以优先获取高强度的安全随机数生成器,如果没有提供,再使用普通等级的安全随机数生成器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Test{
public static void main(String[] args) {
SecureRandom sr = null;
try {
sr = SecureRandom.getInstanceStrong(); // 获取高强度安全随机数生成器
} catch (NoSuchAlgorithmException e) {
sr = new SecureRandom(); // 获取普通的安全随机数生成器
}
byte[] buffer = new byte[16];
sr.nextBytes(buffer); // 用安全随机数填充buffer
System.out.println(Arrays.toString(buffer));
System.out.println(sr.nextInt());
}
}

SecureRandom 的安全性是通过操作系统提供的安全的随机种子来生成随机数。这个种子是通过CPU的热噪声、读写磁盘的字节、网络流量等各种随机事件产生的“熵”。

在密码学中,安全的随机数非常重要。如果使用不安全的伪随机数,所有加密体系都将被攻破。因此,时刻牢记必须使用 SecureRandom 来产生安全的随机数。