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关键字 ...
随机推荐
- java hadoop file system API
org.apache.hadoop.fs Class FileSystem java.lang.Object org.apache.hadoop.fs.FileSystem All Implement ...
- [D3] Creating a D3 Force Layout in React
Learn how to leverage d3's layout module to create a Force Layout inside of React. We'll take a look ...
- java中volatile关键字的含义--volatile并不能做到线程安全
在Java线程并发处理中,有一个关键字volatile的使用目前存在很大的混淆,以为使用这个关键字,在进行多线程并发处理的时候就可以万事大吉. Java语言是支持多线程的,为了解决线程并发的问题,在语 ...
- Android RxJava基本流程和lift源码分析
基本结构 我们先来看一段最基本的代码,分析这段代码在RxJava中是如何实现的. Observable.OnSubscribe<String> onSubscriber1 = new Ob ...
- 【CS Round #48 (Div. 2 only)】8 Divisible
[链接]h在这里写链接 [题意] 给你一个长度为n的数字(n<=1000) 然后让你任意组合这个数字. 使得这个数字能被8整除. (不能出现前导0) [题解] 只要后三位能被8整除就可以了. 则 ...
- LA-3708 - Graveyard 简单的模拟一下即可
一开始不知道在想啥,竟然写了个双重for循环的.T T一直WA,又没效率. T T然后在纸上模拟演算,改了,就AC了 以后做题果断要先模拟一下例子...能加深对题目的理解. 当教训吧..太懒导致写了好 ...
- 3、在编译过程中出现no space left on device
原因:通过df -h查看发现磁盘空间不错 删掉不需要的文件后执行sudo apt-get clean
- CSU1656: Paper of FlyBrother(后缀数组)
Description FlyBrother is a superman, therefore he is always busy saving the world. To graduate fro ...
- win32程序如何改变字体大小颜色
//设定文字大小和颜色 LOGFONT logfont; //改变输出字体 ZeroMemory(&logfont, sizeof(LOGFONT)); logfont.lfCharSet = ...
- 【t052】冰岛
Time Limit: 1 second Memory Limit: 128 MB [问题描述] 假设你在一个n*n的冰面上,并且你想到达这个冰面的某处,可是由于冰面太滑了,所以当你向某个方向出发后, ...