引介
在本地生成不重复字符,该方式能够保证字符数量大概在 9 - 17这个区间,生成的字符完全不重复,无需要数据库验重操作。生成逻辑是根据时间戳进行生成,所以对于生成的字符完全不会重复,对于生成随机字符串的方式有很多,如果你是想通过将生成的所有字符串存放本地,之后再次生成的时候做一个验重操作的话,重启应用或者服务器就失效了,目前我这种方式,即使你重启服务器或者应用,仍然不会受到影响,因为使用的是动态变化的时间戳对象。注意:这种方式生成的字符一般是用于作为一些文档或者分类等数据进行唯一标识的编码。当然也可以通过UUID等方式进行生成随机并且固定长度,但是这种方式能尽量缩小字符串的数量。如果只是想生成6位不重复的字符或者直接递增的,建议直接通过查库的方式来进行生成随机并验证重复。
代码
/**
* +_! 用于生成不会重复的唯一编码对象工具。
*
* @Author tblack.cn
* @Date 2021/2/5 13:35
* @Version 1.0
*/
public class NumberCodeUtil {
public static final String DEFAULT_DATE_FORMAT = "yyyyMMddHHmmssSSS";
public static String generatorNumberCode(Date date) {
SimpleDateFormat ssf = new SimpleDateFormat(DEFAULT_DATE_FORMAT);
char[] chars = StringUtil.getAlphabet(); //拿到A-Z 和 a-z。自定义工具类,甚至可以自己追加 0-9 或者其他字符来优化,如果数组内不重复的字符越多,那么则生成最优字符串的几率会越大。
StringBuffer uniqueCode = new StringBuffer(); //唯一字符串
String timestamp = ssf.format(date); //格式化当前日期
//默认按照每两位数字成一个字符
int count = timestamp.length() % 2 == 0 ? timestamp.length() / 2 : timestamp.length() / 2 + 1;
//循环开始生成随机字符
for (int j = 0; j < count; ++j) {
int b = j * 2; //开始数字下标
int e = (j + 1) * 2; //结束数字下标
if (e > timestamp.length()) //超出长度取最大长度
e = timestamp.length();
//拿到当前的数字
Integer n = Integer.valueOf(timestamp.substring(b, e));
//如果数字大于当前随机字符串数组大小的话。则按照十位和个位分别取值
if (n > chars.length - 1) {
int n1 = n / 10; //取10位
int n2 = n % 10; //取个位
uniqueCode.append(chars[n1]);
uniqueCode.append(chars[n2]);
} else if (n < 10 && (e - b == 2)) { //如果数字小于10并且获取长度为两位的时候,表示存在一个前导0. 如01会自动变为1.那么我们则需要手动对于前导0进行追加字符
uniqueCode.append(chars[0]); //追加前导0字符
uniqueCode.append(chars[n]); //追加当前下标字符
} else {
uniqueCode.append(chars[n]); //追加下标字符
}
}
uniqueCode = new StringBuffer(uniqueCode.reverse());
return uniqueCode.toString();
}
}
测试
public static void main(String[] args) throws InterruptedException {
SimpleDateFormat ssf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
// System.err.println(ssf.format(date));
char[] chars = StringUtil.getAlphabet();
Set<String> set = new HashSet<>();
Set<String> set2 = new HashSet<>();
Map<String,String> map = new HashMap<>();
int min = 100;
int max = 0;
for(int i = 0; i < 100000; ++i){
Date date = new Date();
String uniqueCode = NumberCodeUtil.generatorNumberCode(date);
String timestamp = ssf.format(date);
System.err.println(uniqueCode);
if(uniqueCode.length() < min)
min = uniqueCode.length();
if(uniqueCode.length() > max)
max = uniqueCode.length();
if(set.contains(uniqueCode.toString())){
System.err.println("重复的: " + uniqueCode);
System.err.println("重复的2: " + timestamp);
System.err.println("之前的timestamp: " + map.get(uniqueCode.toString()));
}
map.put(uniqueCode.toString(),timestamp);
set.add(uniqueCode.toString());
set2.add(timestamp);
Thread.sleep(1);
}
System.err.println("Set:" + set.size());
System.err.println("Set2:" + set2.size());
System.err.println("最长: " + max);
System.err.println("最短: " + min);
}
结果
运行十万次检测:
生成的随机码长度取决于当前的时间,在最优情况下,每两个数字生成一个字符,会形成9个长度的随机字符。在最坏情况下,每个数字都会对应生成一个字符,也就是17个字符,但是年份一般不会出现这种情况,所以基本上最多15个字符左右。