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

  • 相关阅读:
    关于返回上一页功能
    Mybatis Update statement Date null
    SQLite reset password
    Bootstrap Validator使用特性,动态(Dynamic)添加的input的验证问题
    Eclipse使用Maven2的一次环境清理记录
    Server Tomcat v7.0 Server at localhost failed to start
    PowerShell一例
    Server Tomcat v7.0 Server at libra failed to start
    商标注册英语
    A glance for agile method
  • 原文地址:https://www.cnblogs.com/jpfss/p/9628711.html
Copyright © 2011-2022 走看看