在使用到uuid的时候,往往头疼于它的长度(如1bfe50d8-544e-4e8a-95b8-199ceff15268),于是乎就有了改写uuid的各种方法

1.去除“-”的uuid

不觉得uuid很长,但是就是看着中间的“-”很难受,又占长度,简单直接点就是

UUID uuid = UUID.randomUUID();
uuid.toString.replace("-", "");


额,这种方法,简单粗暴不优雅,其实呢,还可以看看这个“-”是哪里来的:

    public String toString() {
return (digits(mostSigBits >> 32, 8) + "-" +
digits(mostSigBits >> 16, 4) + "-" +
digits(mostSigBits, 4) + "-" +
digits(leastSigBits >> 48, 4) + "-" +
digits(leastSigBits, 12));
}
/** Returns val represented by the specified number of hex digits. */
private static String digits(long val, int digits) {
long hi = 1L << (digits * 4);
return Long.toHexString(hi | (val & (hi - 1))).substring(1);
}


源码里写的很清楚 是它自己干的,所以完全可以自己实现把“-”去掉(最终代码在后面)

2.21-22位的uuid

去掉“-”之后变成了9b8a013583ba42cba75a9f3d6471eb7a,是一个16进制的字符串,但还是太长

    /*
* The most significant 64 bits of this UUID.
*
* @serial
*/
private final long mostSigBits;

/*
* The least significant 64 bits of this UUID.
*
* @serial
*/
private final long leastSigBits;


源码中的UUID类中的这两个long型属性(mostSigBits是前半部分,leastSigBits是后半部分),其实就代表了uuid,具体的字符串编码都是通过这两个long拼接起来的(不得不说,想法很鸡贼,正常看到的就是这两个的16进制字符串)。

有人说,那直接把“-”去掉使用base64转化成64进制的字符串不就短了很多了?是这样的,不过我们可以仿写base64的实现写个简单的(主要base64最后是拿“+”和“/”凑的64个,“/”在http传输中容易被误解析)

最终的UUIDUtils代码:

import java.util.Date;
import java.util.UUID;

/**
* Created by Kowalski on 2017/5/11
* Updated by Kowalski on 2017/5/11
*/
public final class UUIDUtils {


/**
* 采用URL Base64字符,即把“+/”换成“-_”
*/
private static final char[] digits = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_=".toCharArray();

/**21-22位UUID*/
public static String generateMost22UUID() {

UUID uid = UUID.randomUUID();
long most = uid.getMostSignificantBits();

char[] buf = new char[22];
int charPos = 22;
int radix = 1 << 6;
long mask = radix - 1;
do {
charPos--;
buf[charPos] = digits[(int)(most & mask)];
most >>>= 6;
} while (most != 0);

long least = uid.getLeastSignificantBits();
do {
charPos--;
buf[charPos] = digits[(int)(least & mask)];
least >>>= 6;
} while (least != 0);
return new String(buf, charPos, 22-charPos);
}

/**无 - UUID*/
public static String generateUUID() {
UUID uuid = UUID.randomUUID();
long most = uuid.getMostSignificantBits();

long least = uuid.getLeastSignificantBits();

return (digits(most >> 32, 8) +
digits(most >> 16, 4) +
digits(most, 4) +
digits(least >> 48, 4) +
digits(least, 12));
}

private static String digits(long val, int digits) {
long hi = 1L << (digits << 2);
return Long.toHexString(hi | (val & (hi - 1)));
}

/**22位UUID*/
public static String generateUUID22() {
UUID uuid = UUID.randomUUID();
long msb = uuid.getMostSignificantBits();
long lsb = uuid.getLeastSignificantBits();
char[] out = new char[24];
int tmp = 0, idx = 0;
// 循环写法
int bit = 0, bt1 = 8, bt2 = 8;
int mask = 0x00, offsetm = 0, offsetl = 0;

for(; bit < 16; bit += 3, idx += 4) {
offsetm = 64 - ((bit + 3) << 3);
offsetl = 0;
tmp = 0;

if(bt1 > 3) {
mask = (1 << 8 * 3) - 1;
} else if(bt1 >= 0) {
mask = (1 << 8 * bt1) - 1;
bt2 -= 3 - bt1;
} else {
mask = (1 << 8 * ((bt2 > 3) ? 3 : bt2)) - 1;
bt2 -= 3;
}
if(bt1 > 0) {
bt1 -= 3;
tmp = (int) ((offsetm < 0) ? msb : (msb >>> offsetm) & mask);
if(bt1 < 0) {
tmp <<= Math.abs(offsetm);
mask = (1 << 8 * Math.abs(bt1)) - 1;
}
}
if(offsetm < 0) {
offsetl = 64 + offsetm;
tmp |= ((offsetl < 0) ? lsb : (lsb >>> offsetl)) & mask;
}

if(bit == 15) {
out[idx + 3] = digits[64];
out[idx + 2] = digits[64];
tmp <<= 4;
} else {
out[idx + 3] = digits[tmp & 0x3f];
tmp >>= 6;
out[idx + 2] = digits[tmp & 0x3f];
tmp >>= 6;
}
out[idx + 1] = digits[tmp & 0x3f];
tmp >>= 6;
out[idx] = digits[tmp & 0x3f];
}

return new String(out, 0, 22);
}

public static void main(String... args) {

Date d5 = new Date();
for(int i = 0; i < 10000000; i++) {
generateUUID22();
}
Date d6 = new Date();
System.out.print(d6.getTime() - d5.getTime());
System.out.println("\n");

Date d1 = new Date();
for(int i = 0; i < 10000000; i++) {
generateMost22UUID();
}
Date d2 = new Date();
System.out.print(d2.getTime() - d1.getTime());
System.out.println("\n");
}

}


这种实现方式比用replace后再用base64转换速度要更快(接近一倍),这里都是为了保证uuid的精度实现的,对uuid精度要求较低的也可以使用其他位数更少的uuid变体,有更好方案的小伙伴来交流~