SecureRandom生成12位确认码却得到17位的原因及优化方案
问题原因分析
你的代码逻辑存在关键问题:secureRandom.nextInt(1000000)生成的是0到999999之间的整数,这个整数转换为字符串时长度不固定(比如生成5时是1位,生成123时是3位,生成999999时是6位)。循环仅判断当前字符串长度是否小于12,当最后一次追加的随机数字符串长度超过剩余需要的位数时,最终结果长度就会超过12位。
举个例子:假设前两次追加后字符串长度是11位,此时满足length < 12的条件,会再执行一次循环,追加一个6位的数字串,最终长度就变成11+6=17位,这就是你得到17位结果的原因。
更优实现方式
下面提供几种可靠的固定12位随机数字确认码实现方式:
方式一:逐个生成随机数字(直观易读)
直接循环12次,每次生成0-9的随机数字,拼接成字符串:
private String getEsignConfirmNum() { SecureRandom secureRandom = new SecureRandom(); StringBuilder sb = new StringBuilder(12); // 预先指定容量提升性能 for (int i = 0; i < 12; i++) { // 生成0-9的随机数字 int digit = secureRandom.nextInt(10); sb.append(digit); } return sb.toString(); }
方式二:生成范围随机数+格式化补零
生成0到10^12 - 1之间的随机数,然后使用String.format补前导零,确保长度为12位:
private String getEsignConfirmNum() { SecureRandom secureRandom = new SecureRandom(); // 生成0到999999999999(含)之间的随机数 long randomNum = secureRandom.nextLong(1000000000000L); // 格式化补前导零,确保12位 return String.format("%012d", randomNum); }
注意:
SecureRandom.nextLong(long bound)是Java 8及以上版本支持的方法,低版本可通过secureRandom.nextInt()结合位运算生成范围值,优先推荐高版本API。
方式三:基于字节数组生成(性能更优)
利用SecureRandom生成字节数组,将字节转换为数字后截取前12位:
private String getEsignConfirmNum() { SecureRandom secureRandom = new SecureRandom(); byte[] bytes = new byte[6]; // 6字节足够生成12位数字(每个字节可映射到2位数字) secureRandom.nextBytes(bytes); StringBuilder sb = new StringBuilder(12); for (byte b : bytes) { // 将字节转为0-99的整数,避免负数 int num = (b & 0xFF) % 100; // 补前导零后取两位,拼接 sb.append(String.format("%02d", num)); } return sb.toString(); }
另外,建议使用StringBuilder代替字符串拼接(esignConfirmNum += randomNumber),因为字符串拼接会频繁创建新对象,影响性能,尤其是循环次数较多时。
内容的提问来源于stack exchange,提问作者newPHPDev
相关产品推荐
相关产品推荐

