views:

646

answers:

4

Hi,

I'm looking for the best way to create a unique ID as a String in Java.

Any guidance appreciated, thanks.

I should mention I'm using Java 5.

+4  A: 

java.util.UUID : toString() method

Mitch Wheat
+1 for being the fastest. ;-)
Malax
+14  A: 

Try creating a UUID

String uniqueID = UUID.randomUUID().toString();
aperkins
+1. for the better example! :)
Mitch Wheat
It's not *all* that human readable tho...
pjp
@pjp: a truely randomly generated ID usually isn't human-readable. And making it human-readable usually makes it longer which in turn makes it less human-readable.
Joachim Sauer
I wasn't aware he wanted a human readable unique ID ... that would increase the difficulty quite a bit
aperkins
Another note - if you only need application uniqueness, and AtomicInteger (as noted by Michael Borgwardt) is a much better option, but if you need global uniqueness, a UUID is a much better bet.
aperkins
Thanks this is all I need for now - although Adamski's answer was very good too and I may need something more like that in future.
Supertux
+5  A: 

If you want short, human-readable IDs and only need them to be unique per JVM run:

private static long idCounter = 0;

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

Edit: Alternative suggested in the comments - this relies on under-the-hood "magic" for thread safety, but is more scalable and just as safe:

private static AtomicLong idCounter = new AtomicLong();

public static String createID()
{
    return String.valueOf(idCounter.getAndIncrement());
}
Michael Borgwardt
Or alternatively you could use an `AtomicInteger`
pjp
I prefer Michael's method to the UUID approach as sequential IDs are more typically useful / easier when debugging. Also, UUID.randomUUID() isn't 100% guaranteed to return a unique value.
Adamski
@Adamski: this method will only create unique values as long as you don't restart the JVM, have only 1 JVM running and as long as the counter doesn't overflow. All those assumptions can easily be broken. UUID.randomUUID() is actually more reliable in those situations.
Joachim Sauer
While it is not 100% guaranteed, the odds are so low of you colliding with anyone (as the entire space is larger than the number of atoms estimated to exist in the Universe) as to be 100% guaranteed. And if you need global uniqueness, it is the easiest way to achieve that. However, if you only need local uniqueness (i.e. to a current existing application) then AtomicInteger is definitely the way to go.
aperkins
+3  A: 

Here's my two cent's worth: I've previously implemented an IdFactory class that created IDs in the format [host name]-[application start time]-[current time]-[discriminator]. This largely guaranteed that IDs were unique across JVM instances whilst keeping the IDs readable (albeit quite long). Here's the code in case it's of any use:

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());
    }
  }
}
Adamski