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

1.去除“-”的uuid

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

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

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

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

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

2.21-22位的uuid

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

  1. /*
  2. * The most significant 64 bits of this UUID.
  3. *
  4. * @serial
  5. */
  6. private final long mostSigBits;
  7. /*
  8. * The least significant 64 bits of this UUID.
  9. *
  10. * @serial
  11. */
  12. private final long leastSigBits;

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

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

最终的UUIDUtils代码:

  1. import java.util.Date;
  2. import java.util.UUID;
  3. /**
  4. * Created by Kowalski on 2017/5/11
  5. * Updated by Kowalski on 2017/5/11
  6. */
  7. public final class UUIDUtils {
  8. /**
  9. * 采用URL Base64字符,即把“+/”换成“-_”
  10. */
  11. private static final char[] digits = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_=".toCharArray();
  12. /**21-22位UUID*/
  13. public static String generateMost22UUID() {
  14. UUID uid = UUID.randomUUID();
  15. long most = uid.getMostSignificantBits();
  16. char[] buf = new char[22];
  17. int charPos = 22;
  18. int radix = 1 << 6;
  19. long mask = radix - 1;
  20. do {
  21. charPos--;
  22. buf[charPos] = digits[(int)(most & mask)];
  23. most >>>= 6;
  24. } while (most != 0);
  25. long least = uid.getLeastSignificantBits();
  26. do {
  27. charPos--;
  28. buf[charPos] = digits[(int)(least & mask)];
  29. least >>>= 6;
  30. } while (least != 0);
  31. return new String(buf, charPos, 22-charPos);
  32. }
  33. /**无 - UUID*/
  34. public static String generateUUID() {
  35. UUID uuid = UUID.randomUUID();
  36. long most = uuid.getMostSignificantBits();
  37. long least = uuid.getLeastSignificantBits();
  38. return (digits(most >> 32, 8) +
  39. digits(most >> 16, 4) +
  40. digits(most, 4) +
  41. digits(least >> 48, 4) +
  42. digits(least, 12));
  43. }
  44. private static String digits(long val, int digits) {
  45. long hi = 1L << (digits << 2);
  46. return Long.toHexString(hi | (val & (hi - 1)));
  47. }
  48. /**22位UUID*/
  49. public static String generateUUID22() {
  50. UUID uuid = UUID.randomUUID();
  51. long msb = uuid.getMostSignificantBits();
  52. long lsb = uuid.getLeastSignificantBits();
  53. char[] out = new char[24];
  54. int tmp = 0, idx = 0;
  55. // 循环写法
  56. int bit = 0, bt1 = 8, bt2 = 8;
  57. int mask = 0x00, offsetm = 0, offsetl = 0;
  58. for(; bit < 16; bit += 3, idx += 4) {
  59. offsetm = 64 - ((bit + 3) << 3);
  60. offsetl = 0;
  61. tmp = 0;
  62. if(bt1 > 3) {
  63. mask = (1 << 8 * 3) - 1;
  64. } else if(bt1 >= 0) {
  65. mask = (1 << 8 * bt1) - 1;
  66. bt2 -= 3 - bt1;
  67. } else {
  68. mask = (1 << 8 * ((bt2 > 3) ? 3 : bt2)) - 1;
  69. bt2 -= 3;
  70. }
  71. if(bt1 > 0) {
  72. bt1 -= 3;
  73. tmp = (int) ((offsetm < 0) ? msb : (msb >>> offsetm) & mask);
  74. if(bt1 < 0) {
  75. tmp <<= Math.abs(offsetm);
  76. mask = (1 << 8 * Math.abs(bt1)) - 1;
  77. }
  78. }
  79. if(offsetm < 0) {
  80. offsetl = 64 + offsetm;
  81. tmp |= ((offsetl < 0) ? lsb : (lsb >>> offsetl)) & mask;
  82. }
  83. if(bit == 15) {
  84. out[idx + 3] = digits[64];
  85. out[idx + 2] = digits[64];
  86. tmp <<= 4;
  87. } else {
  88. out[idx + 3] = digits[tmp & 0x3f];
  89. tmp >>= 6;
  90. out[idx + 2] = digits[tmp & 0x3f];
  91. tmp >>= 6;
  92. }
  93. out[idx + 1] = digits[tmp & 0x3f];
  94. tmp >>= 6;
  95. out[idx] = digits[tmp & 0x3f];
  96. }
  97. return new String(out, 0, 22);
  98. }
  99. public static void main(String... args) {
  100. Date d5 = new Date();
  101. for(int i = 0; i < 10000000; i++) {
  102. generateUUID22();
  103. }
  104. Date d6 = new Date();
  105. System.out.print(d6.getTime() - d5.getTime());
  106. System.out.println("\n");
  107. Date d1 = new Date();
  108. for(int i = 0; i < 10000000; i++) {
  109. generateMost22UUID();
  110. }
  111. Date d2 = new Date();
  112. System.out.print(d2.getTime() - d1.getTime());
  113. System.out.println("\n");
  114. }
  115. }

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

UUID不失精度,长度改进的更多相关文章

  1. 【转】JAVA程序中Float和Double精度丢失问题

    原文网址:http://blog.sina.com.cn/s/blog_827d041701017ctm.html 问题提出:12.0f-11.9f=0.10000038,"减不尽" ...

  2. Java double和 float丢失精度问题

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt357 由于对float或double 的使用不当,可能会出现精度丢失的问题. ...

  3. java float double精度为什么会丢失?浅谈java的浮点数精度问题 【转】

    由于对float或double 的使用不当,可能会出现精度丢失的问题.问题大概情况可以通过如下代码理解: public class FloatDoubleTest { public static vo ...

  4. 分布式UUID的生成

    背景 最近有个项目:涉及到分布式计算,tps相对较高,流程之间是异步调用,流程间相互依赖的对象(涉及记录外键)需要持久化.这就衍生出了需要在JVM中快速生成分布式UUID的问题 方案 1.通过JDK标 ...

  5. float,double等精度丢失问题 float,double内存表示

    问题提出:12.0f-11.9f=0.10000038,"减不尽"为什么? 来自MSDN的解释: http://msdn.microsoft.com/zh-cn/c151dt3s. ...

  6. %.*lf控制输出长度

    #include<stdio.h> int main(){    int a,b,c;    while(scanf("%d%d%d",&a,&b,&a ...

  7. MySQL内置函数uuid和uuid_short

    MySQL的uuid这个函数.简要介绍一下. 用法 简单看到,这个值,每次执行都是不同的. 生成规则 第1 2 3 段是与时间有关的. time_low.time_mid.time_high_and_ ...

  8. JavaWeb网上图书商城完整项目-CommonUtils(1生成uuid,2Map转换成JavaBean)

    java工程中添加上面的jar包 CommonUtils类就两个方法: l  String uuid():生成长度32的随机字符,通常用来做实体类的ID.底层使用了UUID类完成: l  T toBe ...

  9. C++基础_总结

    (1)多态性都有哪些?(静态和动态,然后分别叙述了一下虚函数和函数重载) 多态分为两种:静态和动态.静态主要包括函数重载和模板:动态主要是依靠虚函数实现的. 静态联编:重载函数不加virtual关键字 ...

随机推荐

  1. Mongodb总结2-Java版本的HelloWorld-CRUD例子

    2013年,写的CRUD太简单了,今天在原来的基础上,稍微完善了下,用了更多语法,比如排序sort.in语句等. 参考了<Mongodb权威指南-第1版-高清>,等下上传到CSDN下载频道 ...

  2. asp.net mvc 中的自定义验证(Custom Validation Attribute)

    前言

  3. Git 基本使用方法

    Git有一个优点,在本地的每个项目都是一个完整的仓库,除了须要从网络拉取和推送到网络之外,其它全部的操作都能够在本地完毕. 本文简单地介绍怎样在本地使用Git来对文件进行管理,下一篇文章再来说一下分支 ...

  4. Linux下开启关闭防火墙

    一.Linux下开启/关闭防火墙命令 1) 永久性生效,重启后不会复原 开启: chkconfig iptables on 关闭: chkconfig iptables off   2) 即时生效,重 ...

  5. 从零开始使用git第三篇:git撤销操作、分支操作和常见冲突

    从零开始使用git 第三篇:git撤销操作.分支操作和常见冲突 第一篇:从零开始使用git第一篇:下载安装配置 第二篇:从零开始使用git第二篇:git实践操作 第三篇:从零开始使用git第三篇:gi ...

  6. 【Codeforces Round #435 (Div. 2) A】Mahmoud and Ehab and the MEX

    [链接]h在这里写链接 [题意] 在这里写题意 [题解] 让x没有出现,以及0..x-1都出现就可以了. [错的次数] 0 [反思] 在这了写反思 [代码] #include <bits/std ...

  7. ios日期比较

    +(int)compareDate:(NSDate *)date1 date:(NSDate *)date2 { NSDateFormatter *dateFormatter = [[NSDateFo ...

  8. keil快捷键

  9. Visual Studio 项目目录下的bin目录和 obj目录

    一.Bin目录 Visual Studio 编译时,在bin 目录下有debug 和 release 目录. 1.Debug: 通常称为调试版本,它包含调试信息,所以要比Release 版本大很多(可 ...

  10. ios开发多线程二:NSOperationQueue的基本使用

    #import "ViewController.h" #import "XMGOperation.h" @interface ViewController () ...