zoukankan      html  css  js  c++  java
  • 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("
    ");
    
            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("
    ");
        }
    
    }

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

  • 相关阅读:
    exit()和_exit()函数(转)
    C语言struct内存占用问题 (转)
    C语言中memset函数(转)
    STDIN_FILENO与stdin区别(转)
    stderr,strerror,errno,perror,论坛大神的回答!
    C++ 函数模版
    C++ 内置函数
    offsetof
    LockSupportDemo
    读写锁,await和signa
  • 原文地址:https://www.cnblogs.com/jpfss/p/9628711.html
Copyright © 2011-2022 走看看