如何在Java中创建唯一标识符?

215
我正在寻找在Java中创建唯一ID字符串的最佳方法。 任何指导将不胜感激,谢谢。 我应该提到我正在使用Java 5。

看一下这个 https://stackoverflow.com/a/9176060/1737819 。 - Developer Marius Žilėnas
11个回答

431

创建一个UUID

String uniqueID = UUID.randomUUID().toString();

6
虽然不是完全易懂的人类语言... - pjp
18
一个真正随机生成的ID通常是不可读的。而让它变得可读通常会使其变长,进而使其更不易于阅读。 - Joachim Sauer
8
我不知道他想要一个可读的独特ID...这会增加相当多的难度。 - aperkins
2
为什么我们不能使用 System.currentTimeMillis 来生成单调递增的序列并添加一些随机正整数盐? - Farhad
1
除了当前的毫秒建议之外,如果您的应用程序在不同的服务器上运行或移动服务器,则系统时钟可能会有所不同。因此,基于系统时钟的 ID 可能会变成重复的。 - FishingIsLife
显示剩余2条评论

57

如果你想要短小易读的ID,并且只需要它们在每个JVM运行中是唯一的:

private static long idCounter = 0;

public static synchronized String createID()
{
    return String.valueOf(idCounter++);
}    

编辑:评论中提出的替代方法-这依赖于底层的“魔法”来保证线程安全,但更具可扩展性并且同样安全:

private static AtomicLong idCounter = new AtomicLong();

public static String createID()
{
    return String.valueOf(idCounter.getAndIncrement());
}

2
我更喜欢迈克尔的方法而不是UUID方法,因为当调试时连续ID通常更有用/更容易。另外,UUID.randomUUID()不能 100%保证返回唯一值。 - Adamski
17
只要不重新启动JVM,只运行1个JVM并且计数器不溢出,这种方法就可以创建唯一的值。所有这些假设都很容易被打破。在这些情况下,UUID.randomUUID()实际上更可靠。 - Joachim Sauer
3
虽然没有100%的保证,但你与任何人碰撞的概率非常低(因为整个空间比估计存在于宇宙中的原子数量还要大),以至于可以100%地保证。如果您需要全球唯一性,这是最简单的方法。但是,如果您只需要本地唯一性(即对于当前现有的应用程序),那么AtomicInteger肯定是正确的选择。 - aperkins

25

19

以下是我的建议:我以前实现了一个IdFactory类,它以格式[主机名]-[应用程序启动时间]-[当前时间]-[鉴别器]创建ID。这基本上保证了在不同JVM实例之间ID的唯一性,同时保持ID可读性(尽管相当长)。以下是代码,如果有用的话:

public class IdFactoryImpl implements IdFactory {
  private final String hostName;
  private final long creationTimeMillis;
  private long lastTimeMillis;
  private long discriminator;

  public IdFactoryImpl() throws UnknownHostException {
    this.hostName = InetAddress.getLocalHost().getHostAddress();
    this.creationTimeMillis = System.currentTimeMillis();
    this.lastTimeMillis = creationTimeMillis;
  }

  public synchronized Serializable createId() {
    String id;
    long now = System.currentTimeMillis();

    if (now == lastTimeMillis) {
      ++discriminator;
    } else {
      discriminator = 0;
    }

    // creationTimeMillis used to prevent multiple instances of the JVM
    // running on the same host returning clashing IDs.
    // The only way a clash could occur is if the applications started at
    // exactly the same time.
    id = String.format("%s-%d-%d-%d", hostName, creationTimeMillis, now, discriminator);
    lastTimeMillis = now;

    return id;
  }

  public static void main(String[] args) throws UnknownHostException {
    IdFactory fact = new IdFactoryImpl();

    for (int i=0; i<1000; ++i) {
      System.err.println(fact.createId());
    }
  }
}

14

使用Java生成唯一标识

UUID是在Java中生成唯一标识的最快、最简单的方法。

import java.util.UUID;

public class UniqueIDTest {
  public static void main(String[] args) {
    UUID uniqueKey = UUID.randomUUID();
    System.out.println (uniqueKey);
  }
}

9

我认为aperkins提供的解决方案很优雅,因为它是本地的并且使用的代码更少。但是如果您需要更短的ID,您可以采用以下方法来减小生成的字符串长度:

// usage: GenerateShortUUID.next();
import java.util.UUID;

public class GenerateShortUUID() {

  private GenerateShortUUID() { } // singleton

  public static String next() {
     UUID u = UUID.randomUUID();
     return toIDString(u.getMostSignificantBits()) + toIDString(u.getLeastSignificantBits());
  }

  private static String toIDString(long i) {
      char[] buf = new char[32];
      int z = 64; // 1 << 6;
      int cp = 32;
      long b = z - 1;
      do {
          buf[--cp] = DIGITS66[(int)(i & b)];
          i >>>= 6;
      } while (i != 0);
      return new String(buf, cp, (32-cp));
  }

 // array de 64+2 digitos 
 private final static char[] DIGITS66 = {
    '0','1','2','3','4','5','6','7','8','9',        'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
    'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
    '-','.','_','~'
  };

}

这段代码包含一些复杂的行,但生成漂亮的易读ID。有人可以解释一下它是如何全局工作的吗? - Tinus Tate

8
这会在UUID生成过程中增加一些随机性,但确保每个生成的ID长度相同。
import org.apache.commons.codec.digest.DigestUtils;
import java.util.UUID;

public String createSalt() {
    String ts = String.valueOf(System.currentTimeMillis());
    String rand = UUID.randomUUID().toString();
    return DigestUtils.sha1Hex(ts + rand);
}

1
我喜欢额外的currentTimeMillis,它真的使这个随机。 - Mercury
11
UUID.randomUUID() 已经使用“密码学强度”的随机数生成器生成了ID。添加“更多的随机性”意味着什么?在基于纪元时间的随机“盐”附加后会得到什么? - Dan
1
如果我没记错的话,UUID.randomUUID() 在创建随机 ID 时已经使用了时间因素。 - Paramvir Singh Karwal

5
我们可以使用UUID在Java中创建一个唯一的ID,然后调用UUID.randomUUID()方法即可。
String uniqueID = UUID.randomUUID().toString();

这将生成随机的uniqueID,其返回类型为String

2

在Java中,有三种生成唯一ID的方法。

1)UUID类提供了一种简单的生成唯一ID的方式。

 UUID id = UUID.randomUUID();
 System.out.println(id);

2) SecureRandom and MessageDigest

//initialization of the application
 SecureRandom prng = SecureRandom.getInstance("SHA1PRNG");

//generate a random number
 String randomNum = new Integer(prng.nextInt()).toString();

//get its digest
 MessageDigest sha = MessageDigest.getInstance("SHA-1");
 byte[] result =  sha.digest(randomNum.getBytes());

System.out.println("Random number: " + randomNum);
System.out.println("Message digest: " + new String(result));

3) 使用 java.rmi.server.UID

UID userId = new UID();
System.out.println("userId: " + userId);

1
String name,password;

public int idGen() {

    int id = this.name.hashCode() + this.password.hashCode();
    int length = String.valueOf(id).length();
    int Max_Length = 5;
    if(String.valueOf(id).length()>Max_Length) 
    {
        id = (int) (id /Math.pow(10.0,length - Max_Length ));
    }
    return  id;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接