A Java library for generating Universally Unique Lexicographically Sortable Identifiers (ULID)
Go to file
Fabio Lima aad72e2f11 Optimize comparison and hash #20 2022-08-21 07:43:11 -03:00
benchmark Optimize comparison and hash #20 2022-08-21 07:24:10 -03:00
src Optimize comparison and hash #20 2022-08-21 07:24:10 -03:00
.gitignore Updated pom.xml to use commons 2020-03-15 05:17:00 -03:00
CHANGELOG.md Optimize comparison and hash #20 2022-08-21 07:43:11 -03:00
LICENSE handle clock drift #18 2022-04-21 21:34:33 -03:00
README.md Optimize comparison and hash #20 2022-08-21 07:43:11 -03:00
pom.xml [maven-release-plugin] prepare for next development iteration 2022-08-21 07:36:59 -03:00

README.md

ULID Creator

This is a Java implementation of Universally Unique Lexicographically Sortable Identifier.

In summary:

  • Sorted by generation time;
  • Can be stored as a UUID/GUID;
  • Can be stored as a string of 26 chars;
  • Can be stored as an array of 16 bytes;
  • String format is encoded to Crockford's base32;
  • String format is URL safe, is case insensitive, and has no hyphens.

This library contains a good amount of unit tests. It also has a micro benchmark for you to check if the performance is good enough.

How to Use

Create a ULID:

Ulid ulid = UlidCreator.getUlid();

Create a Monotonic ULID:

Ulid ulid = UlidCreator.getMonotonicUlid();

Maven dependency

Add these lines to your pom.xml.

<!-- https://search.maven.org/artifact/com.github.f4b6a3/ulid-creator -->
<dependency>
  <groupId>com.github.f4b6a3</groupId>
  <artifactId>ulid-creator</artifactId>
  <version>5.0.1</version>
</dependency>

See more options in maven.org.

Modularity

Module and bundle names are the same as the root package name.

  • JPMS module name: com.github.f4b6a3.ulid
  • OSGi symbolic name: com.github.f4b6a3.ulid

ULID

The ULID is a 128 bit long identifier. The first 48 bits represent the number of milliseconds since Unix Epoch, 1970-01-01. The remaining 80 bits are generated by a secure random number generator. Its canonical string representation is 26 characters long.

// Generate a ULID
Ulid ulid = UlidCreator.getUlid();

Sequence of ULIDs:

01EX8Y21KBH49ZZCA7KSKH6X1C
01EX8Y21KBJTFK0JV5J20QPQNR
01EX8Y21KBG2CS1V6WQCTVM7K6
01EX8Y21KB8HPZNBP3PTW7HVEY
01EX8Y21KB3HZV38VAPTPAG1TY
01EX8Y21KB9FTEJHPAGAKYG9Z8
01EX8Y21KBQGKGH2SVPQAYEFFC
01EX8Y21KBY17J9WR9KQR8SE7H
01EX8Y21KCVHYSJGVK4HBXDMR9 < millisecond changed
01EX8Y21KC668W3PEDEAGDHMVG
01EX8Y21KC53D2S5ADQ2EST327
01EX8Y21KCPQ3TENMTY1S7HV56
01EX8Y21KC3755QF9STQEV05EB
01EX8Y21KC5ZSHK908GMDK69WE
01EX8Y21KCSGJS8S1FVS06B3SX
01EX8Y21KC6ZBWQ0JBV337R1CN
         ^ look

|---------|--------------|
    time      random

Monotonic ULID

The Monotonic ULID is variant of ULID. The random component is incremented by 1 whenever the current millisecond is equal to the previous one. Its main advantage is speed.

// Generate a Monotonic ULID
Ulid ulid = UlidCreator.getMonotonicUlid();

Sequence of Monotonic ULIDs:

01EX8Y7M8MDVX3M3EQG69EEMJW
01EX8Y7M8MDVX3M3EQG69EEMJX
01EX8Y7M8MDVX3M3EQG69EEMJY
01EX8Y7M8MDVX3M3EQG69EEMJZ
01EX8Y7M8MDVX3M3EQG69EEMK0
01EX8Y7M8MDVX3M3EQG69EEMK1
01EX8Y7M8MDVX3M3EQG69EEMK2
01EX8Y7M8MDVX3M3EQG69EEMK3
01EX8Y7M8N1G30CYF2PJR23J2J < millisecond changed
01EX8Y7M8N1G30CYF2PJR23J2K
01EX8Y7M8N1G30CYF2PJR23J2M
01EX8Y7M8N1G30CYF2PJR23J2N
01EX8Y7M8N1G30CYF2PJR23J2P
01EX8Y7M8N1G30CYF2PJR23J2Q
01EX8Y7M8N1G30CYF2PJR23J2R
01EX8Y7M8N1G30CYF2PJR23J2S
         ^ look          ^ look

|---------|--------------|
    time      random

More Examples

Create a ULID from a canonical string (26 chars):

Ulid ulid = Ulid.from("0123456789ABCDEFGHJKMNPQRS");

Convert a ULID into a canonical string in lower case:

String string = ulid.toLowerCase(); // 0123456789abcdefghjkmnpqrs

Convert a ULID into a UUID:

UUID uuid = ulid.toUuid(); // 0110c853-1d09-52d8-d73e-1194e95b5f19

Convert a ULID into a RFC-4122 UUID v4:

UUID uuid = ulid.toRfc4122().toUuid(); // 0110c853-1d09-42d8-973e-1194e95b5f19
                                       //               ^ UUID v4

Get the creation instant of a ULID:

Instant instant = ulid.getInstant(); // 2007-02-16T02:13:14.633Z
// static method
Instant instant = Ulid.getInstant("0123456789ABCDEFGHJKMNPQRS"); // 2007-02-16T02:13:14.633Z

A key generator that makes substitution easy if necessary:

package com.example;

import com.github.f4b6a3.ulid.UlidCreator;

public class KeyGenerator {
    public static String next() {
        return UlidCreator.getUlid().toString();
    }
}
String key = KeyGenerator.next();

A UlidFactory with java.util.Random:

// use a `java.util.Random` instance for fast generation
UlidFactory factory = UlidFactory.newInstance(new Random());
Ulid ulid = factory.create();

// use the factory

A UlidFactory with SplittableRandom:

// use a random function that returns a long value
SplittableRandom random = new SplittableRandom();
UlidFactory factory = UlidFactory.newInstance(() -> random.nextLong());

// use the factory
Ulid ulid = factory.create();

A UlidFactory with RandomGenerator (JDK 17+):

// use a random function that returns a long value
RandomGenerator random = RandomGenerator.getDefault();
UlidFactory factory = UlidFactory.newInstance(() -> random.nextLong());

// use the factory
Ulid ulid = factory.create();

A UlidFactory with ThreadLocalRandom:

// use a random supplier that returns an array of 10 bytes
UlidFactory factory = UlidFactory.newInstance((length) -> {
    final byte[] bytes = new byte[length];
    ThreadLocalRandom.current().nextBytes(bytes);
    return bytes;
});

// use the factory
Ulid ulid = factory.create();

Benchmark

This section shows benchmarks comparing UlidCreator to java.util.UUID.

--------------------------------------------------------------------------------
THROUGHPUT (operations/msec)            Mode  Cnt      Score     Error   Units
--------------------------------------------------------------------------------
UUID_randomUUID                        thrpt    5   2060,570 ±  37,242  ops/ms
UUID_randomUUID_toString               thrpt    5   1177,386 ±  39,803  ops/ms
-  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
UlidCreator_getUlid                    thrpt    5   2740,609 ±  86,350  ops/ms
UlidCreator_getUlid_toString           thrpt    5   2526,284 ±  56,726  ops/ms
-  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -  -
UlidCreator_getMonotonicUlid           thrpt    5  19373,150 ± 192,402  ops/ms
UlidCreator_getMonotonicUlid_toString  thrpt    5  13269,201 ± 254,953  ops/ms
--------------------------------------------------------------------------------
Total time: 00:08:01
--------------------------------------------------------------------------------

System: JVM 8, Ubuntu 20.04, CPU i5-3330, 8G RAM.

To execute the benchmark, run ./benchmark/run.sh.

Other identifier generators

Check out the other ID generators from the same family:

License

This library is Open Source software released under the MIT license.