最近想做个小项目练手额。本类用于生成用户的数字ID。不知道逻辑对不对,贴上来请各位大牛指教
先上需求:
生成用户数字ID
入参:ID长度、开头数字
出餐:生成的ID
要求说明:
根据【ID长度】生成指定位数的用户ID。
根据【开头数字】生成开头数字一定的ID
再上代码:(PS:最后再稍微解释一下)
1.主要逻辑类
public class UserIDWorker {
private static UserIDWorker userIDWorker;
private Integer sumBit;//总长度
private String beginWith;//指定开头
DecimalFormat df = null;//格式工具
private StringBuilder formating;
private int endLenth;//累加数位
private int count; //每次生成后的终止数字
Set<String> iDSet;//ID集合
private UserIDWorker() {
// TODO Auto-generated constructor stub
}
public static synchronized UserIDWorker getIdSingleton(){
if(userIDWorker == null) {
userIDWorker = new UserIDWorker();
}
return userIDWorker;
}
/**
* @Description: 获取一个ID
* @Author: Shijy
* @Date: 2018/9/8 17:56
*/
public String getter(){
String result = null;
if(iDSet == null || iDSet.isEmpty()){
getNumId();
}
List<String> idList = new ArrayList<>(iDSet);
result = idList.get(0);
iDSet.remove(result);
return result;
}
/**
* @Description: 生成ID集合
* @Author: Shijy
* @Date: 2018/9/8 17:41
*/
private String getNumId(){
try {
checkSetParam(UserConstant.SUMBIT,UserConstant.BEGINWITH);
} catch (CreateIDException e) {
e.printStackTrace();
}
//生成ID的容器
if(iDSet == null){
iDSet = new HashSet<String>();
}
//累加数位(后几位)
this.endLenth = sumBit - beginWith.length();
//累加位数的最大数 (后几位最大数)
Integer max = (int) ((1*(Math.pow(10,endLenth)))-1);
//累加数位补0
if(formating == null || formating.length() == 0){
formating();
}
/*判断该号段是否还可生成ID*/
if(max - count > 0) {
if((count+UserConstant.CREAT_COUNT) <= max) {
//可生成50个及以上
iDSet.clear();
df = new DecimalFormat(formating.toString());
int i = count;
for( ;i < (count + UserConstant.CREAT_COUNT);i++) {
//拼接ID
String endID = df.format(i);
iDSet.add(beginWith+endID);
}
count = i;
}else {
//可生成数不足50个
iDSet.clear();
df = new DecimalFormat(formating.toString());
for(;count < max ;count++) {
//拼接ID
//拼接ID
String endID = df.format(count);
iDSet.add(beginWith+endID);
}
/*已生成完毕该号段ID*/
System.out.println("/*已生成完毕该号段ID*/");
}
}else {
/*已经不能再生成该号段ID*/
System.out.println("/*已经不能再生成该号段ID*/");
//清空set集合
iDSet.clear();
}
return null;
}
/**
* @Description: 累加数位补0
* @Author: Shijy
* @Date: 2018/9/8 17:13
*/
private void formating(){
this.formating = new StringBuilder();
for(int i = 0 ; i < endLenth ; i++) {
formating.append("0");
}
}
/**
* @Description: 检查并设置ID生成策略
* @Author: Shijy
* @Date: 2018/9/8 16:56
*/
private void checkSetParam(Integer sumBit ,String beginWith) throws CreateIDException {
if(sumBit < 3 || sumBit == null) {
throw new CreateIDException("至少生成3位长度的数字ID!!");
}else {
this.sumBit = sumBit;
}
if(StringUtils.isEmpty(beginWith)){
this.beginWith = "1";
}else {
//判断指定开头 是不是纯数字
if(!StringUtils.isNumeric(beginWith)) {
throw new CreateIDException("指定的开头不是纯数字!!");
}
//判断指定开头是不是以0开头
if(beginWith.substring(0, 1).equals("0")) {
throw new CreateIDException("指定的ID不能以0开头!!");
}
//判断指定长度 是否大于 指定开头数字长度
if(sumBit <= beginWith.length()) {
throw new CreateIDException("生成ID长度应大于指定开头数字长度!!");
}
this.beginWith = beginWith;
}
}
/**
* @Description: 自定义异常
* @Author: Shijy
* @Date: 2018/9/8 17:05
*/
class CreateIDException extends Exception{
private static final long serialVersionUID = 1L;
public CreateIDException() {
super();
}
public CreateIDException(String msg) {
super(msg);
}
}
}
2.常量部分
public final class UserConstant {
private UserConstant() {
}
/**用户数字ID生成器常量**/
public static final Integer SUMBIT = 9;//生成ID的长度
public static final String BEGINWITH = "666";//指定开头号段
public static final Integer CREAT_COUNT = 10;//每次生成个数
}
3.调用(for循环生成60000个ID)
public static void main(String[] args) {
for(int i = 0;i < 60000;i++){
String id = UserIDWorker.getIdSingleton().getter();
System.out.println(id);
}
}
稍微解释一下:
1.getter()方法:从ID集合(iDSet)中取出一个ID,判断如果集合中没有数据则调用getNumId()生成,取一个删一个
2.getNumId()方法:生成ID并存入ID集合,本方法中先调用checkSetParam(Integer sumBit ,String beginWith)做需求中“ID长度”与“开头号段”的一些必要校验(代码中有注释,里面如有不通过校验的,这里使用CreateIDException内部类做异常抛出)
3.getNumId()方法中取常量类中一次生成的ID个数。判断该号段是否距离上次生成的最大记录是否还能生成常量类中指定个数个ID,如可以,则生成指定数量的ID,并记录本次生成的最大ID供下次使用。如可生成个数不足指定数量,则不做本次最大ID记录.如果不能生成则设置ID集合为空。
生成方法采用【指定号段】拼接【剩余长度】的策略。剩余长度递增,长度不足则补0
问题:
1.这个方法是不是能保证多线程下生成ID唯一呢?
2.有什么不妥的嘛...
3.可以优化嘛...
4.目前是使用Set集合做相对乱序(实际还是有序...因为...Hash...)有什么好办法实现乱序嘛...
请指教。感谢看官~