更短且不失高效的UUID生成算法


Java原生的UUID長度為36位,嫌長
這里自己實現了一套自己的算法,來生成較短的UUID

由雪花算法啟發而來,
大致原理是利用時間戳+隨機值做值,然后轉換成62進制(當然這個進制數你也可以搞成更多)

有一些參數可以控制一些行為,都在注釋里了

你可以自己修改digits數組,亂亂序啥的,混淆一下,隨機性可能更好一些

/**
 * Java 原生的UUID為36位 or 32位,太長. 這里提供一個位數較短的UUID.
 * <p>
 * UUID生成規則,當前時間減去'零時'的毫秒數 + N位隨機數,轉變成62進制的String類型.
 * <p>
 * 當前配置可滿足30年內每毫秒10^9分之一的碰撞.
 * <p>
 * 實測現在長度為13位,想要更短的話可以調整下方的幾個參數
 *
 * @author libing02 , on 11月 20, 2019.
 */
public class ShortUUID {

    /**
     * digits還可以擴,但是不要包含下面的SEPARATOR
     * <p>
     * 也可以替換一個"亂序"digits排列,最終使uuid看起來不是有序的.
     * <p>
     * 一旦用到生產環境,digits就不要再變動了,否則會出現重復
     * <p>
     */
    private static final char[] digits = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
        .toCharArray();

    private static final char SEPARATOR = '_';

    // 2019-11-15 17:00:00
    private static final long ERA_TIME = 1573808400000L;

    // UUID一次輪回的指數. 12則為大概30年左右,11則為3年左右. 13就是300年
    private static final int TIME_LOOP_INDEX = 12;

    // 碰撞指數.毫秒下萬萬分之一
    private static final int COLLISION_INDEX = 99999999;

    private static final boolean MIX_UP = true;

    public static String randomUUID() {
        long passTime = System.currentTimeMillis() - ERA_TIME;

        long l = passTime;
        // 反轉主要是為了讓uuid看起來不是遞增的
        // 但這也會導致出現極小概率不同時間的碰撞,所以建議優先選擇不反轉
        if (MIX_UP) {
            StringBuilder stringBuilder = new StringBuilder(String.valueOf(passTime)).reverse();
            while (stringBuilder.length() < TIME_LOOP_INDEX) {
                stringBuilder.append('0');
            }
            l = Long.parseLong(stringBuilder.substring(0, TIME_LOOP_INDEX));
        }

        return baseConversion(l, digits.length) + SEPARATOR +
            baseConversion(RandomUtils.ranInt(COLLISION_INDEX), digits.length);
    }

    @Test
    public void test() {
        System.out.println(randomUUID());
    }


    /**
     * 將10進制轉換成任意進制,照着Long原生的進制轉換寫的,原生最大支持到32進制
     * <p>
     * 這里支持到更高進制,可以擴展digits數組實現更高
     *
     * @param i     十進制Long型
     * @param radix 進制,[2-62]
     * @return 轉換后的String
     */
    public static String baseConversion(long i, int radix) {
        if (radix < 2 || radix > digits.length) {
            radix = 10;
        }

        int charPos = digits.length * 2;
        final int size = charPos + 1;

        char[] buf = new char[size];
        boolean negative = (i < 0);

        if (!negative) {
            i = -i;
        }

        while (i <= -radix) {
            buf[charPos--] = digits[(int) (-(i % radix))];
            i = i / radix;
        }
        buf[charPos] = digits[(int) (-i)];

        if (negative) {
            buf[--charPos] = '-';
        }

        return new String(buf, charPos, (size - charPos));
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM