UUID不失精度,长度改进

在使用到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变体,有更好方案的小伙伴来交流~

发布了26 篇原创文章 · 获赞 68 · 访问量 26万+

猜你喜欢

转载自blog.csdn.net/qq_32193151/article/details/71632173
今日推荐