琢磨了一晚上,就为了写一个“不重复的随机码生成函数”,生成格式包含0-9,a-z。
头脑风暴,异想天开,写下了如下算法,看上去很高大上的一个随机生成方法。
原理先产生一个UUID,再根据UUID生成一个随机数,UUID,不重复嘛。一测试,坑爹了,生成100万条长度为4的随机码,重复率达到25%,傻眼了。
/** * 随机码生成 * @author Mo * * @param length 随机码长度 * @return */ public static String random1(int length){ /* * 这里直接数字代替,没用uuid.length() * */ String uuid = UUID.randomUUID().toString().replace("-", ""); int len = uuid.length(); /*定义随机码字符串变量,初始化为""*/ String random = ""; /* * 循环截取UUID * len/length 每次循环截取的字符串长度 * len%length 如果出现32长度除不尽的情况,取余数 * */ int subLen = len/length; int remainder = len%length; /*定义substring的两个参数*/ int start = 0,end = 0; for(int i=0;i<length;i++){ /* * 计算start和end的值 * 这里涉及两种方法,一种是除不尽的时候,将截取长度分散到头部,一种是分散到尾部 * * uuid的前部分是时间戳构成的,因此前部分截取越少,重复率越底 * 固本方法采用了将多余的部分分散到尾部 * */ /*分散到尾部,如length为7的时候4,4,4,4,5,5,5*/ // end = start + (length-i <= remainder ? 1 : 0)+subLen; /*分散到头部,如length为7 的时候5,5,5,5,4,4,4*/ end = start + (i < remainder ? 1 : 0)+subLen; /*截取到的字符串*/ String code = uuid.substring(start,end); /*对所截取的长度进行16位求和*/ int count = 0; for(char c : code.toCharArray()){ count += Integer.valueOf(String.valueOf(c),16); } /*将求和结果转化成36位,并增加到随机码中,36位包含了0-9a-z*/ random += Integer.toString(count%36, 36); start = end; } /*返回随机码*/ return random; }
泡杯咖啡,清醒一下,随机码生成函数2应运而生,小学生(入门级程序员)都能看懂。经过测试,生成100万条长度4的随机码,重复率也在25%左右。
推荐方法:
/** * 随机码生成 * @author Mo * * @param length * @return */ public static String random2(int length){ String random = ""; /*随机数函数*/ java.util.Random r=new java.util.Random(); for(int i = 0;i<length;i++){ /*生成36以内的随机数,不含36,并转化为36位*/ random += Integer.toString(r.nextInt(36), 36); } return random; }
事实证明,最复杂的方法并不是最好的方法,程序开发跟其他的事情一样,不要画蛇添足,时间浪费了,性能浪费了,还得不到好的结果。当然,多尝试是对的。
事后想想,既然是随机生成,又要控制长度,长度为4,又怎么会出现不重复的数字呢。当然,将长度调整到8的时候,重复率基本没有,这个没有也不能绝对,只是说概率降低了而已。
总结:要生成不重复的随机码,必经要经过数据验证,拿新生成的随机码去与历史生成数据对比,如果已存在,则舍弃重新生成。如果对长度没要求,可以直接采用UUID,UUID是国际通用的不重复的串,不过长度达到了36位之多。
以下提供一个自写随机码测试函数:
public static void main(String args []){ Set<String> set = new HashSet<String>(); int times = 1000000; for(int i = 0 ;i<times;i++){ String random = random1(8); set.add(random); } System.out.println("重复了:"+(times-set.size())+"次"); }
关于java的更多交流,请给我留言,简单的问题,也可以很复杂化,只有更深入的去尝试,才能更深刻的理解每一个细节问题。