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变体,有更好方案的小伙伴来交流~
UUID不失精度,长度改进的更多相关文章
- 【转】JAVA程序中Float和Double精度丢失问题
原文网址:http://blog.sina.com.cn/s/blog_827d041701017ctm.html 问题提出:12.0f-11.9f=0.10000038,"减不尽" ...
- Java double和 float丢失精度问题
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt357 由于对float或double 的使用不当,可能会出现精度丢失的问题. ...
- java float double精度为什么会丢失?浅谈java的浮点数精度问题 【转】
由于对float或double 的使用不当,可能会出现精度丢失的问题.问题大概情况可以通过如下代码理解: public class FloatDoubleTest { public static vo ...
- 分布式UUID的生成
背景 最近有个项目:涉及到分布式计算,tps相对较高,流程之间是异步调用,流程间相互依赖的对象(涉及记录外键)需要持久化.这就衍生出了需要在JVM中快速生成分布式UUID的问题 方案 1.通过JDK标 ...
- float,double等精度丢失问题 float,double内存表示
问题提出:12.0f-11.9f=0.10000038,"减不尽"为什么? 来自MSDN的解释: http://msdn.microsoft.com/zh-cn/c151dt3s. ...
- %.*lf控制输出长度
#include<stdio.h> int main(){ int a,b,c; while(scanf("%d%d%d",&a,&b,&a ...
- MySQL内置函数uuid和uuid_short
MySQL的uuid这个函数.简要介绍一下. 用法 简单看到,这个值,每次执行都是不同的. 生成规则 第1 2 3 段是与时间有关的. time_low.time_mid.time_high_and_ ...
- JavaWeb网上图书商城完整项目-CommonUtils(1生成uuid,2Map转换成JavaBean)
java工程中添加上面的jar包 CommonUtils类就两个方法: l String uuid():生成长度32的随机字符,通常用来做实体类的ID.底层使用了UUID类完成: l T toBe ...
- C++基础_总结
(1)多态性都有哪些?(静态和动态,然后分别叙述了一下虚函数和函数重载) 多态分为两种:静态和动态.静态主要包括函数重载和模板:动态主要是依靠虚函数实现的. 静态联编:重载函数不加virtual关键字 ...
随机推荐
- Mongodb总结2-Java版本的HelloWorld-CRUD例子
2013年,写的CRUD太简单了,今天在原来的基础上,稍微完善了下,用了更多语法,比如排序sort.in语句等. 参考了<Mongodb权威指南-第1版-高清>,等下上传到CSDN下载频道 ...
- asp.net mvc 中的自定义验证(Custom Validation Attribute)
前言
- Git 基本使用方法
Git有一个优点,在本地的每个项目都是一个完整的仓库,除了须要从网络拉取和推送到网络之外,其它全部的操作都能够在本地完毕. 本文简单地介绍怎样在本地使用Git来对文件进行管理,下一篇文章再来说一下分支 ...
- Linux下开启关闭防火墙
一.Linux下开启/关闭防火墙命令 1) 永久性生效,重启后不会复原 开启: chkconfig iptables on 关闭: chkconfig iptables off 2) 即时生效,重 ...
- 从零开始使用git第三篇:git撤销操作、分支操作和常见冲突
从零开始使用git 第三篇:git撤销操作.分支操作和常见冲突 第一篇:从零开始使用git第一篇:下载安装配置 第二篇:从零开始使用git第二篇:git实践操作 第三篇:从零开始使用git第三篇:gi ...
- 【Codeforces Round #435 (Div. 2) A】Mahmoud and Ehab and the MEX
[链接]h在这里写链接 [题意] 在这里写题意 [题解] 让x没有出现,以及0..x-1都出现就可以了. [错的次数] 0 [反思] 在这了写反思 [代码] #include <bits/std ...
- ios日期比较
+(int)compareDate:(NSDate *)date1 date:(NSDate *)date2 { NSDateFormatter *dateFormatter = [[NSDateFo ...
- keil快捷键
- Visual Studio 项目目录下的bin目录和 obj目录
一.Bin目录 Visual Studio 编译时,在bin 目录下有debug 和 release 目录. 1.Debug: 通常称为调试版本,它包含调试信息,所以要比Release 版本大很多(可 ...
- ios开发多线程二:NSOperationQueue的基本使用
#import "ViewController.h" #import "XMGOperation.h" @interface ViewController () ...