场景

UUID 是指Universally Unique Identifier,翻译为中文是通用唯一识别码,UUID 的目的是让分布式系统中的所有元素都能有唯一的识别信息。

在某些场景下需要给数据库中存储的某些字段使用唯一标志。

或者需要一些唯一标志的字符串。

注:

博客:
https://blog.csdn.net/badao_liumang_qizhi
关注公众号
霸道的程序猿
获取编程相关电子书、教程推送与免费下载。

实现

首先新建一个ID生成器工具类IdUtils

/*** ID生成器工具类*/
public class IdUtils
{/*** 获取随机UUID** @return 随机UUID*/public static String randomUUID(){return UUID.randomUUID().toString();}/*** 简化的UUID,去掉了横线** @return 简化的UUID,去掉了横线*/public static String simpleUUID(){return UUID.randomUUID().toString(true);}/*** 获取随机UUID,使用性能更好的ThreadLocalRandom生成UUID** @return 随机UUID*/public static String fastUUID(){return UUID.fastUUID().toString();}/*** 简化的UUID,去掉了横线,使用性能更好的ThreadLocalRandom生成UUID** @return 简化的UUID,去掉了横线*/public static String fastSimpleUUID(){return UUID.fastUUID().toString(true);}
}

在这个工具类中调用了UUID这个实现类的一些方法

UUID.java

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;/*** 提供通用唯一识别码(universally unique identifier)(UUID)实现**/
public final class UUID implements java.io.Serializable, Comparable<UUID>
{private static final long serialVersionUID = -1185015143654744140L;/*** SecureRandom 的单例**/private static class Holder{static final SecureRandom numberGenerator = getSecureRandom();}/** 此UUID的最高64有效位 */private final long mostSigBits;/** 此UUID的最低64有效位 */private final long leastSigBits;/*** 私有构造** @param data 数据*/private UUID(byte[] data){long msb = 0;long lsb = 0;assert data.length == 16 : "data must be 16 bytes in length";for (int i = 0; i < 8; i++){msb = (msb << 8) | (data[i] & 0xff);}for (int i = 8; i < 16; i++){lsb = (lsb << 8) | (data[i] & 0xff);}this.mostSigBits = msb;this.leastSigBits = lsb;}/*** 使用指定的数据构造新的 UUID。** @param mostSigBits 用于 {@code UUID} 的最高有效 64 位* @param leastSigBits 用于 {@code UUID} 的最低有效 64 位*/public UUID(long mostSigBits, long leastSigBits){this.mostSigBits = mostSigBits;this.leastSigBits = leastSigBits;}/*** 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的本地线程伪随机数生成器生成该 UUID。** @return 随机生成的 {@code UUID}*/public static UUID fastUUID(){return randomUUID(false);}/*** 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。** @return 随机生成的 {@code UUID}*/public static UUID randomUUID(){return randomUUID(true);}/*** 获取类型 4(伪随机生成的)UUID 的静态工厂。 使用加密的强伪随机数生成器生成该 UUID。** @param isSecure 是否使用{@link SecureRandom}如果是可以获得更安全的随机码,否则可以得到更好的性能* @return 随机生成的 {@code UUID}*/public static UUID randomUUID(boolean isSecure){final Random ng = isSecure ? Holder.numberGenerator : getRandom();byte[] randomBytes = new byte[16];ng.nextBytes(randomBytes);randomBytes[6] &= 0x0f; /* clear version */randomBytes[6] |= 0x40; /* set to version 4 */randomBytes[8] &= 0x3f; /* clear variant */randomBytes[8] |= 0x80; /* set to IETF variant */return new UUID(randomBytes);}/*** 根据指定的字节数组获取类型 3(基于名称的)UUID 的静态工厂。** @param name 用于构造 UUID 的字节数组。** @return 根据指定数组生成的 {@code UUID}*/public static UUID nameUUIDFromBytes(byte[] name){MessageDigest md;try{md = MessageDigest.getInstance("MD5");}catch (NoSuchAlgorithmException nsae){throw new InternalError("MD5 not supported");}byte[] md5Bytes = md.digest(name);md5Bytes[6] &= 0x0f; /* clear version */md5Bytes[6] |= 0x30; /* set to version 3 */md5Bytes[8] &= 0x3f; /* clear variant */md5Bytes[8] |= 0x80; /* set to IETF variant */return new UUID(md5Bytes);}/*** 根据 {@link #toString()} 方法中描述的字符串标准表示形式创建{@code UUID}。** @param name 指定 {@code UUID} 字符串* @return 具有指定值的 {@code UUID}* @throws IllegalArgumentException 如果 name 与 {@link #toString} 中描述的字符串表示形式不符抛出此异常**/public static UUID fromString(String name){String[] components = name.split("-");if (components.length != 5){throw new IllegalArgumentException("Invalid UUID string: " + name);}for (int i = 0; i < 5; i++){components[i] = "0x" + components[i];}long mostSigBits = Long.decode(components[0]).longValue();mostSigBits <<= 16;mostSigBits |= Long.decode(components[1]).longValue();mostSigBits <<= 16;mostSigBits |= Long.decode(components[2]).longValue();long leastSigBits = Long.decode(components[3]).longValue();leastSigBits <<= 48;leastSigBits |= Long.decode(components[4]).longValue();return new UUID(mostSigBits, leastSigBits);}/*** 返回此 UUID 的 128 位值中的最低有效 64 位。** @return 此 UUID 的 128 位值中的最低有效 64 位。*/public long getLeastSignificantBits(){return leastSigBits;}/*** 返回此 UUID 的 128 位值中的最高有效 64 位。** @return 此 UUID 的 128 位值中最高有效 64 位。*/public long getMostSignificantBits(){return mostSigBits;}/*** 与此 {@code UUID} 相关联的版本号. 版本号描述此 {@code UUID} 是如何生成的。* <p>* 版本号具有以下含意:* <ul>* <li>1 基于时间的 UUID* <li>2 DCE 安全 UUID* <li>3 基于名称的 UUID* <li>4 随机生成的 UUID* </ul>** @return 此 {@code UUID} 的版本号*/public int version(){// Version is bits masked by 0x000000000000F000 in MS longreturn (int) ((mostSigBits >> 12) & 0x0f);}/*** 与此 {@code UUID} 相关联的变体号。变体号描述 {@code UUID} 的布局。* <p>* 变体号具有以下含意:* <ul>* <li>0 为 NCS 向后兼容保留* <li>2 <a href="IETF&nbsp;RFC&nbsp;4122(Leach-Salz'" DESIGNTIMESP=969>IETF&nbsp;RFC&nbsp;4122(Leach-Salz'" DESIGNTIMESP=518>http://www.ietf.org/rfc/rfc4122.txt">IETF&nbsp;RFC&nbsp;4122</a>(Leach-Salz), 用于此类* <li>6 保留,微软向后兼容* <li>7 保留供以后定义使用* </ul>** @return 此 {@code UUID} 相关联的变体号*/public int variant(){// This field is composed of a varying number of bits.// 0 - - Reserved for NCS backward compatibility// 1 0 - The IETF aka Leach-Salz variant (used by this class)// 1 1 0 Reserved, Microsoft backward compatibility// 1 1 1 Reserved for future definition.return (int) ((leastSigBits >>> (64 - (leastSigBits >>> 62))) & (leastSigBits >> 63));}/*** 与此 UUID 相关联的时间戳值。** <p>* 60 位的时间戳值根据此 {@code UUID} 的 time_low、time_mid 和 time_hi 字段构造。<br>* 所得到的时间戳以 100 毫微秒为单位,从 UTC(通用协调时间) 1582 年 10 月 15 日零时开始。** <p>* 时间戳值仅在在基于时间的 UUID(其 version 类型为 1)中才有意义。<br>* 如果此 {@code UUID} 不是基于时间的 UUID,则此方法抛出 UnsupportedOperationException。** @throws UnsupportedOperationException 如果此 {@code UUID} 不是 version 为 1 的 UUID。*/public long timestamp() throws UnsupportedOperationException{checkTimeBase();return (mostSigBits & 0x0FFFL) << 48//| ((mostSigBits >> 16) & 0x0FFFFL) << 32//| mostSigBits >>> 32;}/*** 与此 UUID 相关联的时钟序列值。** <p>* 14 位的时钟序列值根据此 UUID 的 clock_seq 字段构造。clock_seq 字段用于保证在基于时间的 UUID 中的时间唯一性。* <p>* {@code clockSequence} 值仅在基于时间的 UUID(其 version 类型为 1)中才有意义。 如果此 UUID 不是基于时间的 UUID,则此方法抛出* UnsupportedOperationException。** @return 此 {@code UUID} 的时钟序列** @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1*/public int clockSequence() throws UnsupportedOperationException{checkTimeBase();return (int) ((leastSigBits & 0x3FFF000000000000L) >>> 48);}/*** 与此 UUID 相关的节点值。** <p>* 48 位的节点值根据此 UUID 的 node 字段构造。此字段旨在用于保存机器的 IEEE 802 地址,该地址用于生成此 UUID 以保证空间唯一性。* <p>* 节点值仅在基于时间的 UUID(其 version 类型为 1)中才有意义。<br>* 如果此 UUID 不是基于时间的 UUID,则此方法抛出 UnsupportedOperationException。** @return 此 {@code UUID} 的节点值** @throws UnsupportedOperationException 如果此 UUID 的 version 不为 1*/public long node() throws UnsupportedOperationException{checkTimeBase();return leastSigBits & 0x0000FFFFFFFFFFFFL;}/*** 返回此{@code UUID} 的字符串表现形式。** <p>* UUID 的字符串表示形式由此 BNF 描述:** <pre>* {@code* UUID                   = <time_low>-<time_mid>-<time_high_and_version>-<variant_and_sequence>-<node>* time_low               = 4*<hexOctet>* time_mid               = 2*<hexOctet>* time_high_and_version  = 2*<hexOctet>* variant_and_sequence   = 2*<hexOctet>* node                   = 6*<hexOctet>* hexOctet               = <hexDigit><hexDigit>* hexDigit               = [0-9a-fA-F]* }* </pre>** </blockquote>** @return 此{@code UUID} 的字符串表现形式* @see #toString(boolean)*/@Overridepublic String toString(){return toString(false);}/*** 返回此{@code UUID} 的字符串表现形式。** <p>* UUID 的字符串表示形式由此 BNF 描述:** <pre>* {@code* UUID                   = <time_low>-<time_mid>-<time_high_and_version>-<variant_and_sequence>-<node>* time_low               = 4*<hexOctet>* time_mid               = 2*<hexOctet>* time_high_and_version  = 2*<hexOctet>* variant_and_sequence   = 2*<hexOctet>* node                   = 6*<hexOctet>* hexOctet               = <hexDigit><hexDigit>* hexDigit               = [0-9a-fA-F]* }* </pre>** </blockquote>** @param isSimple 是否简单模式,简单模式为不带'-'的UUID字符串* @return 此{@code UUID} 的字符串表现形式*/public String toString(boolean isSimple){final StringBuilder builder = new StringBuilder(isSimple ? 32 : 36);// time_lowbuilder.append(digits(mostSigBits >> 32, 8));if (false == isSimple){builder.append('-');}// time_midbuilder.append(digits(mostSigBits >> 16, 4));if (false == isSimple){builder.append('-');}// time_high_and_versionbuilder.append(digits(mostSigBits, 4));if (false == isSimple){builder.append('-');}// variant_and_sequencebuilder.append(digits(leastSigBits >> 48, 4));if (false == isSimple){builder.append('-');}// nodebuilder.append(digits(leastSigBits, 12));return builder.toString();}/*** 返回此 UUID 的哈希码。** @return UUID 的哈希码值。*/@Overridepublic int hashCode(){long hilo = mostSigBits ^ leastSigBits;return ((int) (hilo >> 32)) ^ (int) hilo;}/*** 将此对象与指定对象比较。* <p>* 当且仅当参数不为 {@code null}、而是一个 UUID 对象、具有与此 UUID 相同的 varriant、包含相同的值(每一位均相同)时,结果才为 {@code true}。** @param obj 要与之比较的对象** @return 如果对象相同,则返回 {@code true};否则返回 {@code false}*/@Overridepublic boolean equals(Object obj){if ((null == obj) || (obj.getClass() != UUID.class)){return false;}UUID id = (UUID) obj;return (mostSigBits == id.mostSigBits && leastSigBits == id.leastSigBits);}// Comparison Operations/*** 将此 UUID 与指定的 UUID 比较。** <p>* 如果两个 UUID 不同,且第一个 UUID 的最高有效字段大于第二个 UUID 的对应字段,则第一个 UUID 大于第二个 UUID。** @param val 与此 UUID 比较的 UUID** @return 在此 UUID 小于、等于或大于 val 时,分别返回 -1、0 或 1。**/@Overridepublic int compareTo(UUID val){// The ordering is intentionally set up so that the UUIDs// can simply be numerically compared as two numbersreturn (this.mostSigBits < val.mostSigBits ? -1 : //(this.mostSigBits > val.mostSigBits ? 1 : //(this.leastSigBits < val.leastSigBits ? -1 : //(this.leastSigBits > val.leastSigBits ? 1 : //0))));}// -------------------------------------------------------------------------------------------------------------------// Private method start/*** 返回指定数字对应的hex值** @param val 值* @param digits 位* @return 值*/private static String digits(long val, int digits){long hi = 1L << (digits * 4);return Long.toHexString(hi | (val & (hi - 1))).substring(1);}/*** 检查是否为time-based版本UUID*/private void checkTimeBase(){if (version() != 1){throw new UnsupportedOperationException("Not a time-based UUID");}}/*** 获取{@link SecureRandom},类提供加密的强随机数生成器 (RNG)** @return {@link SecureRandom}*/public static SecureRandom getSecureRandom(){try{return SecureRandom.getInstance("SHA1PRNG");}catch (NoSuchAlgorithmException e){throw new UtilException(e);}}/*** 获取随机数生成器对象<br>* ThreadLocalRandom是JDK 7之后提供并发产生随机数,能够解决多个线程发生的竞争争夺。** @return {@link ThreadLocalRandom}*/public static ThreadLocalRandom getRandom(){return ThreadLocalRandom.current();}
}

这其中又使用了自定义异常类UtilException

public class UtilException extends RuntimeException
{private static final long serialVersionUID = 8247610319171014183L;public UtilException(Throwable e){super(e.getMessage(), e);}public UtilException(String message){super(message);}public UtilException(String message, Throwable throwable){super(message, throwable);}
}

使用示例

String uuid = IdUtils.simpleUUID();

Java中使用UUID工具类生成唯一标志防止重复相关推荐

  1. uuid java 重复_Java中使用UUID工具类生成唯一标志防止重复

    import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.secur ...

  2. 《Java并发编程的艺术》——Java中的并发工具类、线程池、Execute框架(笔记)

    文章目录 八.Java中的并发工具类 8.1 等待多线程完成的CountDownLatch 8.2 同步屏障CyclicBarrier 8.2.1 CyclicBarrier简介 8.2.2 Cycl ...

  3. 《Java并发编程的艺术》读后笔记-Java中的并发工具类(第八章)

    文章目录 <Java并发编程的艺术>读后笔记-Java中的并发工具类(第八章) 1.等待多线程完成的CountDownLatch 2.同步屏障CyclicBarrier 2.1 Cycli ...

  4. java ftp ftpclient_详解JAVA中使用FTPClient工具类上传下载

    详解JAVA中使用FTPClient工具类上传下载 在Java程序中,经常需要和FTP打交道,比如向FTP服务器上传文件.下载文件.本文简单介绍如何利用jakarta commons中的FTPClie ...

  5. java中常用的工具类

    1. 常用零散工具类 1.1[DateUtil.java]日期处理的工具类 /*** 时间日期处理工具* String -> Date* Date -> String* 以及生成含有日期的 ...

  6. Java中的数字工具类-----持续总结中

    标题 java获取任意数字的个位,十位,百位,千位,万位... JAVA实现数值跟人民币大写(中文简体.繁体)互转 Java实现数值金额指定分割符 java代码去除千分号 BigDecimal判空处理 ...

  7. java中常用的工具类(二)FtpUtil, 汉字转拼音,zip工具类,CollectionUtil,MathUtil,

    下面继续分享java中常用的一些工具类,希望给大家带来帮助! 1.FtpUtil Java package com.itjh.javaUtil;import java.io.File; import ...

  8. JAVA中通过时间格式来生成唯一的文件名

    有时候我们需要截图,在要截图时,有人用到了时间格式,但是时间格式中的:在文件名称中是不被允许的字符,所以就会报错,如何生成唯一的时间文件名: package com.demo;import java. ...

  9. Java 中的并发工具类

    From: https://blog.wuwii.com/juc-utils.html java.util.concurrent 下提供了一些辅助类来帮助我们在并发编程的设计. 学习了 AQS 后再了 ...

最新文章

  1. ffmpeg 基本用法大全
  2. QA:智能布线系统二十问
  3. 基于OHCI的USB主机 —— 寄存器(其它)
  4. SQL Server 2012 Managed Service Account
  5. 4、spring核心AOP
  6. 2022年中国品质直播选型与应用白皮书
  7. 打开office 文档慢的小技巧1 更改默认打印机
  8. java.lang.UnsatisfiedLinkError: D:\Tomcat\apache-tomcat-7.0.67\bin\tcnative-1.dll:
  9. 资源 | 我拿到了斯坦福、UCL、CMU、NYU的offer,关于博士申请你需要知道的一切...
  10. javaweb开发后端常用技术_java后端开发需要掌握什么技术
  11. MySQL(1)CentOS彻底卸载MySQL
  12. vue 直传视频到阿里云OSS
  13. 微信开发:账号申请,AppID、AppSecret 获取方式
  14. FOI 冬令营 Day6
  15. [转]禅修程序员十诫
  16. 又一块遮羞布被撕了,5G的发展还是得靠手机用户
  17. poi设置单元格下拉下表
  18. Feign原理:current list of Servers哪里来的
  19. PR AE PS安装资源包
  20. Linux下GPT分区,gdisk修复损坏的分区表

热门文章

  1. 分析对象内部结构,并详解synchronized锁膨胀升级和降级的过程
  2. resultset需要关闭吗_微信视频号能关闭吗?怎么操作?3秒教你搞定
  3. SpringMVC学习(五)——零配置实现SpringMVC
  4. SpringBoot 实现固定、动态定时任务 | 三种实现方式 | 附源代码
  5. es6 取数组的第一个和最后一个_JS算法题之每日一题- 17.在排序数组中查找元素的第一个和最后一个位置...
  6. 利用计算机提高数学课堂教学,计算机技术在数学课堂教学中的应用微探
  7. mysql中标记某条数据库_一个关系数据库表中的各条记录可以什么
  8. zx1 android版本,蔡司发布全画幅卡片机ZX1:安卓系统 内置Lightroom
  9. linux系统怎么用vim,linux/unix
  10. sudo apt-get update后public key is not available公钥不存在问题解决