I worked out the following utility class, with the assistance of an [AI][1] to get the Java Generics correct. This code appears to me to be solid. But not thoroughly tested, nor used in production, so buyer beware.
Some of the checks and guards here may be unnecessary. But better safe than sorry. Also, I suggest adding [*JSpecify*][7] null-check annotations.
Key concepts:
- All the constant objects of an `enum` class can be obtained by calling the implicit `public static T[] values()` method of that class, returning an array. (A fact unfortunately [buried in the Javadoc][2].)
- [`ThreadLocalRandom.current()`][3] returns the current thread's [`ThreadLocalRandom`][4] object, a random number generator isolated that particular thread. So, thread-safe, without contention.
- `ThreadLocalRandom` offers the handy [`nextInt`][5] method taking only an argument of the bound while assuming an origin of zero. Just what we need to access a zero-based index into an array.
```lang-java
public class RandomEnumSelector < EnumSubType extends Enum < EnumSubType > >
{
// Member fields.
// Make these `public` for read-only access by the calling programmer.
public final Class < EnumSubType > enumSubClass;
public final EnumSubType[] values; // most common name for this field
// Constructor.
public RandomEnumSelector ( final Class < EnumSubType > theEnumSubClass )
{
// Validate input.
Objects.requireNonNull( theEnumSubClass );
if ( ! theEnumSubClass.isEnum() ) throw new IllegalArgumentException( theEnumSubClass.getName() + " is not an enum." ); // May be superfluous given our use of generics.
// Initialize member fields.
this.enumSubClass = theEnumSubClass;
this.values = this.enumSubClass.getEnumConstants();
// Validate member fields.
if ( Objects.isNull( this.values ) || this.values.length == 0 ) throw new IllegalArgumentException( theEnumSubClass.getName() + " is not a valid enum with constants." );
}
// Logic.
public EnumSubType random ( )
{
int index = ThreadLocalRandom.current().nextInt( this.values.length );
return this.values[ index ];
}
}
```
Usage example follows. Two steps to using:
- Declare your instance as being of the type of your enum. Ex: `< Letter >`.
- Pass to the constructor the class of your enum. Ex: `Letter.class`.
```lang-java
enum Letter { A, B, C }
RandomEnumSelector < Letter > randomEnumSelector = new RandomEnumSelector <>( Letter.class );
Letter randomLetter = randomEnumSelector.random();
IO.println( randomLetter ); // Before Java 25, swap `System.out.` for `IO`.
```
By the way, as seen above, in Java 16+ you can define an `enum` locally in addition to a nested or separate class. (See [*JEP 395*][6].)
> B
[1]: https://en.wikipedia.org/wiki/Generative_artificial_intelligence
[2]: https://docs.oracle.com/en/java/javase/25/docs/api//java.base/java/lang/Enum.html#valueOf(java.lang.Class,java.lang.String)
[3]: https://docs.oracle.com/en/java/javase/25/docs/api//java.base/java/util/concurrent/ThreadLocalRandom.html#current()
[4]: https://docs.oracle.com/en/java/javase/25/docs/api//java.base/java/util/concurrent/ThreadLocalRandom.html
[5]: https://docs.oracle.com/en/java/javase/25/docs/api//java.base/java/util/concurrent/ThreadLocalRandom.html#nextInt(int)
[6]: https://openjdk.org/jeps/395
[7]: https://jspecify.dev/
## tl;dr
Simply use `ThreadLocalRandom` with `Enum#values` method for this one-liner.
```java
Letter.values()[ ThreadLocalRandom.current().nextInt( Letter.values().length ) ]
```
## `ThreadLocalRandom`
Wow, so many Answers that try too hard.
Let’s build a concise, easy, thread-safe one-liner using `ThreadLocalRandom`.
First, define our example enum.
```lang-java
enum Letter { A , B , C }
```
### One-liner
To select one enum object randomly, know this:
- All the constant objects of an `enum` class can be obtained by calling the implicit `public static T[] values()` method of that class, returning an array. (A fact unfortunately [buried in the Javadoc][1].)
- [`ThreadLocalRandom.current()`][2] returns the current thread's [`ThreadLocalRandom`][3] object, a random number generator isolated that particular thread. So, thread-safe, without contention.
- `ThreadLocalRandom` offers the handy [`nextInt`][4] method taking only the bound while assuming an origin of zero. Just what we need to access a zero-based index into an array.
```lang-java
Letter randomLetter =
Letter // Your `enum` class.
.values() // Returns an array of all the objects defined in your enum.
[ // Square-bracket accesses an element from the array using zero-based index counting.
ThreadLocalRandom // A random-number generator local to a particular thread.
.current() // Access the current thread’s random generator. Thread-safe, without contention.
.nextInt( // Generate an `int` number in range of zero (inclusive) to specified bound (exclusive, Half-Open).
Letter.values().length // Size of array.
) // Returns an `int`, our index into array of enum objects.
] // Returns the randomly-selected object from the enum.
;
```
### Separate utility class
You could easily use that code as a one-liner, wherever you need it. Or we could make a handy little class, where you just pass the class of your `enum`. Besides convenience, we get a tiny bit of optimization by caching the array of enums (though a JDK implementation may already be doing that, I don’t know).
This code makes extensive use of [Java Generics][5] to ensure that we are dealing with an `enum`, which is technically a subclass of [`Enum`][6].
Using Generics as a day-to-day calling programmer is easy. But using Generics in called code is *not* easy. Frankly, I could not have worked out all this Generics code without the assistance of an [AI][7]. But I did work it out, and this class seems to be solid. However, I have not thoroughly tested this code, nor have I used it in production, so buyer-beware. (And, in real work I would add [JSpecify][8] null-check annotations.)
```lang-java
public class RandomEnumSelector < EnumSubType extends Enum < EnumSubType > >
{
// Member fields.
// Make these `public` for read-only access by the calling programmer.
public final Class < EnumSubType > enumSubClass;
public final EnumSubType[] values; // most common name for this field
// Constructor.
public RandomEnumSelector ( final Class < EnumSubType > theEnumSubClass )
{
// Validate input.
Objects.requireNonNull( theEnumSubClass );
if ( ! theEnumSubClass.isEnum() ) throw new IllegalArgumentException( theEnumSubClass.getName() + " is not an enum." ); // May be superfluous given our use of generics.
// Initialize member fields.
this.enumSubClass = theEnumSubClass;
this.values = this.enumSubClass.getEnumConstants();
// Validate member fields.
if ( Objects.isNull( this.values ) || this.values.length == 0 ) throw new IllegalArgumentException( theEnumSubClass.getName() + " is not a valid enum with constants." );
}
// Logic.
public EnumSubType random ( )
{
int index = ThreadLocalRandom.current().nextInt( this.values.length );
return this.values[ index ];
}
}
```
By the way, in Java 16+, you can define an `enum` locally in addition to a nested or separate class. (See [JEP 395][9].)
Let's exercise this class.
```lang-java
enum Letter { A, B, C }
RandomEnumSelector < Letter > randomEnumSelector = new RandomEnumSelector <>( Letter.class );
Letter randomLetter = randomEnumSelector.random();
IO.println( randomLetter );
```
>B
That does indeed work, even with a locally defined `enum`.
[1]: https://docs.oracle.com/en/java/javase/25/docs/api//java.base/java/lang/Enum.html#valueOf(java.lang.Class,java.lang.String)
[2]: https://docs.oracle.com/en/java/javase/25/docs/api//java.base/java/util/concurrent/ThreadLocalRandom.html#current()
[3]: https://docs.oracle.com/en/java/javase/25/docs/api//java.base/java/util/concurrent/ThreadLocalRandom.html
[4]: https://docs.oracle.com/en/java/javase/25/docs/api//java.base/java/util/concurrent/ThreadLocalRandom.html#nextInt(int)
[5]: https://en.wikipedia.org/wiki/Generics_in_Java
[6]: https://docs.oracle.com/en/java/javase/25/docs/api//java.base/java/lang/Enum.html
[7]: https://en.wikipedia.org/wiki/Generative_artificial_intelligence
[8]: https://jspecify.dev/
[9]: https://openjdk.org/jeps/395