Random Port Generator — Java source
Generate one or many random TCP/UDP port numbers across registered, ephemeral, or the full range - optionally unique. Runs entirely in your browser with crypto-grade randomness.
This is the Java implementation — the same logic the interactive tool runs, in a shareable, citable form.
// random-port-generator — Java port: random/dynamic port picker.
//
// Display port of the CosmoDev Random Port Generator tool — same contract as
// cli/random-port-generator/random-port-generator.go (the live Go twin) and
// src/lib/random-port.ts (the canonical TypeScript implementation). An
// injectable RNG makes generation deterministic (the TS test surface);
// invalid custom ranges throw IllegalArgumentException, mirroring the TS
// throw. The default RNG is SecureRandom — a CSPRNG standing in for the TS
// crypto.getRandomValues default.
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;
import java.util.function.DoubleSupplier;
public final class RandomPort {
/** Named ranges — `Range` in the Go twin; REGISTERED is the zero-value default. */
public enum Range { ANY, REGISTERED, EPHEMERAL, CUSTOM }
/** PortOptions in the TS lib (count/unique cover randomPorts). */
public static final class PortOptions {
Range range = Range.REGISTERED; // the TS default (registered ports)
Integer min; // custom-range lower bound
Integer max; // custom-range upper bound
int count = 1;
boolean unique;
DoubleSupplier rng; // injectable random in [0, 1); null = default
public PortOptions range(Range r) { range = r; return this; }
public PortOptions min(int v) { min = v; return this; }
public PortOptions max(int v) { max = v; return this; }
public PortOptions count(int v) { count = v; return this; }
public PortOptions unique(boolean v) { unique = v; return this; }
public PortOptions rng(DoubleSupplier v) { rng = v; return this; }
}
private static final SecureRandom RANDOM = new SecureRandom();
/** defaultRng() in the TS lib: a CSPRNG draw in [0, 1). */
private static double defaultRng() { return RANDOM.nextDouble(); }
/** resolveRange() in the TS lib. */
static int[] resolveRange(PortOptions o) {
if (o.range == Range.CUSTOM) {
return new int[] { o.min != null ? o.min : 1, o.max != null ? o.max : 65535 };
}
switch (o.range) {
case ANY: return new int[] { 1, 65535 };
case EPHEMERAL: return new int[] { 49152, 65535 };
default: return new int[] { 1024, 49151 }; // REGISTERED
}
}
/** assertRange() in the TS lib — the TS Error becomes an exception. */
private static void assertRange(int lo, int hi) {
if (lo < 0 || lo > 65535 || hi > 65535 || lo > hi) {
throw new IllegalArgumentException("Invalid port range " + lo + "-" + hi);
}
}
/** randomPort() in the TS lib — Port() in the Go twin. */
public static int randomPort(PortOptions o) {
DoubleSupplier rng = o.rng != null ? o.rng : RandomPort::defaultRng;
int[] r = resolveRange(o);
assertRange(r[0], r[1]);
return r[0] + (int) Math.floor(rng.getAsDouble() * (r[1] - r[0] + 1));
}
/** randomPorts() in the TS lib — Ports() in the Go twin. */
public static List<Integer> randomPorts(PortOptions o) {
int count = Math.max(1, o.count);
int[] r = resolveRange(o);
assertRange(r[0], r[1]);
List<Integer> out = new ArrayList<>(count);
if (!o.unique) {
for (int i = 0; i < count; i++) out.add(randomPort(o));
return out;
}
// Fisher-Yates partial shuffle over the range to pick n unique ports.
int lo = r[0], hi = r[1];
int capacity = hi - lo + 1;
int n = Math.min(count, capacity);
DoubleSupplier rng = o.rng != null ? o.rng : RandomPort::defaultRng;
int[] pool = new int[capacity];
for (int i = 0; i < capacity; i++) pool[i] = lo + i;
for (int i = 0; i < n; i++) {
int j = i + (int) Math.floor(rng.getAsDouble() * (capacity - i));
int t = pool[i]; pool[i] = pool[j]; pool[j] = t;
}
for (int i = 0; i < n; i++) out.add(pool[i]);
return out;
}
public static void main(String[] args) {
// Vectors from src/lib/random-port.test.ts — a fixed rng pins every draw.
DoubleSupplier zero = () -> 0.0;
System.out.println("registered+0 = " + randomPort(new PortOptions().rng(zero))); // 1024
System.out.println("any+0 = " + randomPort(new PortOptions().range(Range.ANY).rng(zero))); // 1
System.out.println("ephemeral+0 = " + randomPort(new PortOptions().range(Range.EPHEMERAL).rng(zero))); // 49152
System.out.println("custom 8000-8000 @0.9 = "
+ randomPort(new PortOptions().range(Range.CUSTOM).min(8000).max(8000).rng(() -> 0.9))); // 8000
int[] d = resolveRange(new PortOptions().range(Range.CUSTOM));
System.out.println("resolveRange(custom defaults) = " + d[0] + ".." + d[1]); // 1..65535
System.out.println("count=5 @0 = " + randomPorts(new PortOptions().count(5).rng(zero))); // [1024 x5]
System.out.println("unique 3 in 1..10 @0.5 = "
+ randomPorts(new PortOptions().count(3).unique(true).range(Range.CUSTOM).min(1).max(10).rng(() -> 0.5))); // [6, 1, 7]
System.out.println("unique 5 in 1..3 @0.5 = "
+ randomPorts(new PortOptions().count(5).unique(true).range(Range.CUSTOM).min(1).max(3).rng(() -> 0.5))); // capped at capacity 3
int p = randomPort(new PortOptions()); // default CSPRNG, registered range
System.out.println("default rng registered = " + p + " (in 1024..49151)");
for (PortOptions bad : new PortOptions[] {
new PortOptions().range(Range.CUSTOM).min(70000),
new PortOptions().range(Range.CUSTOM).min(100).max(50),
}) {
try {
randomPort(bad);
} catch (IllegalArgumentException e) {
System.out.println("invalid: " + e.getMessage());
}
}
}
}
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →