Zufällige Daten in Java generieren

1. Übersicht

In diesem Tutorial erfahren Sie, wie Sie zufällige Daten und Zeiten auf begrenzte und unbegrenzte Weise generieren.

Wir werden uns ansehen, wie diese Werte mithilfe der alten java.util.Date- API und der neuen Datums- / Uhrzeitbibliothek aus Java 8 generiert werden .

2. Zufälliges Datum und Uhrzeit

Daten und Zeiten sind im Vergleich zu einer Epochenzeit nichts anderes als 32-Bit-Ganzzahlen. Mit diesem einfachen Algorithmus können wir also zufällige zeitliche Werte generieren:

  1. Generieren Sie eine zufällige 32-Bit-Zahl, eine int
  2. Übergeben Sie den generierten Zufallswert an einen geeigneten Konstruktor oder Builder für Datum und Uhrzeit

2.1. Bounded Sofort

java.time.I nstant ist eine der neuen Ergänzungen für Datum und Uhrzeit in Java 8. Sie repräsentieren Momentanpunkte auf der Zeitachse .

Um einen zufälligen Instant zwischen zwei anderen zu generieren , können wir:

  1. Generieren Sie eine Zufallszahl zwischen den Epochensekunden der angegebenen Instants
  2. Erstellen Sie den zufälligen Instant, indem Sie diese Zufallszahl an die ofEpochSecond () -Methode übergeben
public static Instant between(Instant startInclusive, Instant endExclusive) { long startSeconds = startInclusive.getEpochSecond(); long endSeconds = endExclusive.getEpochSecond(); long random = ThreadLocalRandom .current() .nextLong(startSeconds, endSeconds); return Instant.ofEpochSecond(random); }

Um in Umgebungen mit mehreren Threads einen höheren Durchsatz zu erzielen, verwenden wir ThreadLocalRandom , um unsere Zufallszahlen zu generieren.

Wir können überprüfen, ob der generierte Instant immer größer oder gleich dem ersten Instant und kleiner als der zweite Instant ist:

Instant hundredYearsAgo = Instant.now().minus(Duration.ofDays(100 * 365)); Instant tenDaysAgo = Instant.now().minus(Duration.ofDays(10)); Instant random = RandomDateTimes.between(hundredYearsAgo, tenDaysAgo); assertThat(random).isBetween(hundredYearsAgo, tenDaysAgo);

Denken Sie natürlich daran, dass das Testen der Zufälligkeit von Natur aus nicht deterministisch ist und in einer realen Anwendung im Allgemeinen nicht empfohlen wird.

In ähnlicher Weise ist es auch möglich, einen zufälligen Instant nach oder vor einem anderen zu generieren :

public static Instant after(Instant startInclusive) { return between(startInclusive, Instant.MAX); } public static Instant before(Instant upperExclusive) { return between(Instant.MIN, upperExclusive); }

2.2. Begrenztes Datum

Einer der Konstruktoren java.util.Date benötigt die Anzahl der Millisekunden nach der Epoche. Wir können also denselben Algorithmus verwenden, um ein zufälliges Datum zwischen zwei anderen zu generieren :

public static Date between(Date startInclusive, Date endExclusive) { long startMillis = startInclusive.getTime(); long endMillis = endExclusive.getTime(); long randomMillisSinceEpoch = ThreadLocalRandom .current() .nextLong(startMillis, endMillis); return new Date(randomMillisSinceEpoch); }

Ebenso sollten wir dieses Verhalten überprüfen können:

long aDay = TimeUnit.DAYS.toMillis(1); long now = new Date().getTime(); Date hundredYearsAgo = new Date(now - aDay * 365 * 100); Date tenDaysAgo = new Date(now - aDay * 10); Date random = LegacyRandomDateTimes.between(hundredYearsAgo, tenDaysAgo); assertThat(random).isBetween(hundredYearsAgo, tenDaysAgo);

2.3. Ungebundener Instant

Um einen völlig zufälligen Instant zu generieren , können wir einfach eine zufällige Ganzzahl generieren und diese an die ofEpochSecond () -Methode übergeben:

public static Instant timestamp() { return Instant.ofEpochSecond(ThreadLocalRandom.current().nextInt()); }

Wenn Sie 32-Bit-Sekunden verwenden, da die Epochenzeit vernünftigere Zufallszeiten generiert, verwenden wir hier die nextInt () -Methode .

Außerdem sollte dieser Wert immer noch zwischen den minimal und maximal möglichen Sofortwerten liegen, die Java verarbeiten kann:

Instant random = RandomDateTimes.timestamp(); assertThat(random).isBetween(Instant.MIN, Instant.MAX);

2.4. Ungebundenes Datum

Ähnlich wie im begrenzten Beispiel können wir einen zufälligen Wert an den Konstruktor von Date übergeben , um ein zufälliges Datum zu generieren :

public static Date timestamp() { return new Date(ThreadLocalRandom.current().nextInt() * 1000L); }

Seit derDie Zeiteinheit des Konstruktors ist Millisekunden. Wir konvertieren die 32-Bit-Epochensekunden in Millisekunden, indem wir sie mit 1000 multiplizieren.

Sicherlich liegt dieser Wert immer noch zwischen den minimal und maximal möglichen Datumswerten :

Date MIN_DATE = new Date(Long.MIN_VALUE); Date MAX_DATE = new Date(Long.MAX_VALUE); Date random = LegacyRandomDateTimes.timestamp(); assertThat(random).isBetween(MIN_DATE, MAX_DATE);

3. Zufälliges Datum

Bisher haben wir zufällige Zeitwerte generiert, die sowohl Datums- als auch Zeitkomponenten enthalten. In ähnlicher Weise können wir das Konzept der Epochentage verwenden, um zufällige Zeitwerte mit nur Datumskomponenten zu generieren.

Ein Epochentag entspricht der Anzahl der Tage seit dem 1. Januar 1970. Um ein zufälliges Datum zu generieren, müssen wir nur eine Zufallszahl generieren und diese Zahl als Epochentag verwenden.

3.1. Eingeschränkt

Wir brauchen eine zeitliche Abstraktion, die nur Datumskomponenten enthält, daher scheint java.time.LocalDate ein guter Kandidat zu sein:

public static LocalDate between(LocalDate startInclusive, LocalDate endExclusive) { long startEpochDay = startInclusive.toEpochDay(); long endEpochDay = endExclusive.toEpochDay(); long randomDay = ThreadLocalRandom .current() .nextLong(startEpochDay, endEpochDay); return LocalDate.ofEpochDay(randomDay); }

Hier verwenden wir die toEpochDay () -Methode, um jedes LocalDate in den entsprechenden Epochentag zu konvertieren . Ebenso können wir überprüfen, ob dieser Ansatz korrekt ist:

LocalDate start = LocalDate.of(1989, Month.OCTOBER, 14); LocalDate end = LocalDate.now(); LocalDate random = RandomDates.between(start, end); assertThat(random).isBetween(start, end);

3.2. Ungebunden

Um zufällige Daten unabhängig von einem Bereich zu generieren, können wir einfach einen zufälligen Epochentag generieren:

public static LocalDate date() { int hundredYears = 100 * 365; return LocalDate.ofEpochDay(ThreadLocalRandom .current().nextInt(-hundredYears, hundredYears)); }

Unser Zufallsdatengenerator wählt einen zufälligen Tag aus 100 Jahren vor und nach der Epoche. Auch hier besteht das Grundprinzip darin, angemessene Datumswerte zu generieren:

LocalDate randomDay = RandomDates.date(); assertThat(randomDay).isBetween(LocalDate.MIN, LocalDate.MAX);

4. Zufällige Zeit

Ähnlich wie bei Datumsangaben können wir zufällige Zeitwerte nur mit Zeitkomponenten generieren. Dazu können wir das Konzept des zweiten Tages verwenden. Das heißt, eine zufällige Zeit entspricht einer Zufallszahl, die die Sekunden seit Beginn des Tages darstellt.

4.1. Eingeschränkt

Die Klasse java.time.LocalTime ist eine zeitliche Abstraktion, die nur Zeitkomponenten enthält:

public static LocalTime between(LocalTime startTime, LocalTime endTime) { int startSeconds = startTime.toSecondOfDay(); int endSeconds = endTime.toSecondOfDay(); int randomTime = ThreadLocalRandom .current() .nextInt(startSeconds, endSeconds); return LocalTime.ofSecondOfDay(randomTime); }

Um eine zufällige Zeit zwischen zwei anderen zu erzeugen, können wir:

  1. Generieren Sie eine Zufallszahl zwischen der Sekunde des Tages der angegebenen Zeiten
  2. Erstellen Sie eine zufällige Zeit mit dieser Zufallszahl

Wir können das Verhalten dieses Algorithmus zur zufälligen Zeitgenerierung leicht überprüfen:

LocalTime morning = LocalTime.of(8, 30); LocalTime randomTime = RandomTimes.between(LocalTime.MIDNIGHT, morning); assertThat(randomTime) .isBetween(LocalTime.MIDNIGHT, morning) .isBetween(LocalTime.MIN, LocalTime.MAX);

4.2. Ungebunden

Selbst unbegrenzte Zeitwerte sollten im Bereich von 00:00:00 bis 23:59:59 liegen, damit wir diese Logik einfach durch Delegierung implementieren können:

public static LocalTime time() { return between(LocalTime.MIN, LocalTime.MAX); }

5. Schlussfolgerung

In diesem Tutorial haben wir die Definition von zufälligen Daten und Zeiten auf zufällige Zahlen reduziert. Dann haben wir gesehen, wie diese Reduzierung uns geholfen hat, zufällige zeitliche Werte zu generieren, die sich wie Zeitstempel, Daten oder Zeiten verhalten.

Wie üblich ist der Beispielcode auf GitHub verfügbar.