Skip to content

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 →