Source code
Description: source: package: org.apache.commons.lang3, class: RandomUtils

    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *     http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017package org.apache.commons.lang3;
    018
    019import java.security.NoSuchAlgorithmException;
    020import java.security.SecureRandom;
    021import java.security.Security;
    022import java.util.Random;
    023import java.util.concurrent.ThreadLocalRandom;
    024import java.util.function.Supplier;
    025
    026import org.apache.commons.lang3.exception.UncheckedException;
    027
    028/**
    029 * Supplements the standard {@link Random} class.
    030 * <p>
    031 * Use {@link #secure()} to get the singleton instance based on {@link SecureRandom#SecureRandom()} which uses a secure random number generator implementing the
    032 * default random number algorithm.
    033 * </p>
    034 * <p>
    035 * Use {@link #secureStrong()} to get the singleton instance based on {@link SecureRandom#getInstanceStrong()} which uses an instance that was selected by using
    036 * the algorithms/providers specified in the {@code securerandom.strongAlgorithms} {@link Security} property.
    037 * </p>
    038 * <p>
    039 * Use {@link #insecure()} to get the singleton instance based on {@link ThreadLocalRandom#current()} <b>which is not cryptographically secure</b>. In addition,
    040 * instances do not use a cryptographically random seed unless the {@linkplain System#getProperty system property} {@code java.util.secureRandomSeed} is set to
    041 * {@code true}.
    042 * </p>
    043 * <p>
    044 * Starting in version 3.17.0, the method {@link #secure()} uses {@link SecureRandom#SecureRandom()} instead of {@link SecureRandom#getInstanceStrong()}, and
    045 * adds {@link #secureStrong()}.
    046 * </p>
    047 * <p>
    048 * Starting in version 3.16.0, this class uses {@link #secure()} for static methods and adds {@link #insecure()}.
    049 * </p>
    050 * <p>
    051 * Starting in version 3.15.0, this class uses {@link SecureRandom#getInstanceStrong()} for static methods.
    052 * </p>
    053 * <p>
    054 * Before version 3.15.0, this class used {@link ThreadLocalRandom#current()} for static methods, which is not cryptographically secure.
    055 * </p>
    056 * <p>
    057 * Please note that the Apache Commons project provides a component dedicated to pseudo-random number generation, namely
    058 * <a href="https://commons.apache.org/proper/commons-rng/">Commons RNG</a>, that may be a better choice for applications with more stringent requirements
    059 * (performance and/or correctness).
    060 * </p>
    061 *
    062 * @see #secure()
    063 * @see #secureStrong()
    064 * @see #insecure()
    065 * @see SecureRandom#SecureRandom()
    066 * @see SecureRandom#getInstanceStrong()
    067 * @see ThreadLocalRandom#current()
    068 * @see RandomStringUtils
    069 * @since 3.3
    070 */
    071public class RandomUtils {
    072
    073    private static RandomUtils INSECURE = new RandomUtils(ThreadLocalRandom::current);
    074
    075    private static RandomUtils SECURE = new RandomUtils(SecureRandom::new);
    076
    077    private static final Supplier<Random> SECURE_STRONG_SUPPLIER = () -> RandomUtils.SECURE_RANDOM_STRONG.get();
    078
    079    private static RandomUtils SECURE_STRONG = new RandomUtils(SECURE_STRONG_SUPPLIER);
    080
    081    private static final ThreadLocal<SecureRandom> SECURE_RANDOM_STRONG = ThreadLocal.withInitial(() -> {
    082        try {
    083            return SecureRandom.getInstanceStrong();
    084        } catch (final NoSuchAlgorithmException e) {
    085            throw new UncheckedException(e);
    086        }
    087    });
    088
    089    /**
    090     * Gets the singleton instance based on {@link ThreadLocalRandom#current()}; <b>which is not cryptographically
    091     * secure</b>; use {@link #secure()} to use an algorithms/providers specified in the
    092     * {@code securerandom.strongAlgorithms} {@link Security} property.
    093     * <p>
    094     * The method {@link ThreadLocalRandom#current()} is called on-demand.
    095     * </p>
    096     *
    097     * @return the singleton instance based on {@link ThreadLocalRandom#current()}.
    098     * @see ThreadLocalRandom#current()
    099     * @see #secure()
    100     * @since 3.17.0
    101     */
    102    public static RandomUtils insecure() {
    103        return INSECURE;
    104    }
    105
    106    /**
    107     * Generates a random boolean value.
    108     *
    109     * @return the random boolean
    110     * @since 3.5
    111     * @deprecated Use {@link #secure()}, {@link #secureStrong()},or {@link #insecure()}.
    112     */
    113    @Deprecated
    114    public static boolean nextBoolean() {
    115        return secure().randomBoolean();
    116    }
    117
    118    /**
    119     * Generates an array of random bytes.
    120     *
    121     * @param count the size of the returned array
    122     * @return the random byte array
    123     * @throws IllegalArgumentException if {@code count} is negative
    124     * @deprecated Use {@link #secure()}, {@link #secureStrong()},or {@link #insecure()}.
    125     */
    126    @Deprecated
    127    public static byte[] nextBytes(final int count) {
    128        return secure().randomBytes(count);
    129    }
    130
    131    /**
    132     * Generates a random double between 0 (inclusive) and Double.MAX_VALUE (exclusive).
    133     *
    134     * @return the random double
    135     * @see #nextDouble(double, double)
    136     * @since 3.5
    137     * @deprecated Use {@link #secure()}, {@link #secureStrong()},or {@link #insecure()}.
    138     */
    139    @Deprecated
    140    public static double nextDouble() {
    141        return secure().randomDouble();
    142    }
    143
    144    /**
    145     * Generates a random double within the specified range.
    146     *
    147     * @param startInclusive the smallest value that can be returned, must be non-negative
    148     * @param endExclusive   the upper bound (not included)
    149     * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is
    150     *                                  negative
    151     * @return the random double
    152     * @deprecated Use {@link #secure()}, {@link #secureStrong()},or {@link #insecure()}.
    153     */
    154    @Deprecated
    155    public static double nextDouble(final double startInclusive, final double endExclusive) {
    156        return secure().randomDouble(startInclusive, endExclusive);
    157    }
    158
    159    /**
    160     * Generates a random float between 0 (inclusive) and Float.MAX_VALUE (exclusive).
    161     *
    162     * @return the random float
    163     * @see #nextFloat(float, float)
    164     * @since 3.5
    165     * @deprecated Use {@link #secure()}, {@link #secureStrong()},or {@link #insecure()}.
    166     */
    167    @Deprecated
    168    public static float nextFloat() {
    169        return secure().randomFloat();
    170    }
    171
    172    /**
    173     * Generates a random float within the specified range.
    174     *
    175     * @param startInclusive the smallest value that can be returned, must be non-negative
    176     * @param endExclusive   the upper bound (not included)
    177     * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is
    178     *                                  negative
    179     * @return the random float
    180     * @deprecated Use {@link #secure()}, {@link #secureStrong()},or {@link #insecure()}.
    181     */
    182    @Deprecated
    183    public static float nextFloat(final float startInclusive, final float endExclusive) {
    184        return secure().randomFloat(startInclusive, endExclusive);
    185    }
    186
    187    /**
    188     * Generates a random int between 0 (inclusive) and Integer.MAX_VALUE (exclusive).
    189     *
    190     * @return the random integer
    191     * @see #nextInt(int, int)
    192     * @since 3.5
    193     * @deprecated Use {@link #secure()}, {@link #secureStrong()},or {@link #insecure()}.
    194     */
    195    @Deprecated
    196    public static int nextInt() {
    197        return secure().randomInt();
    198    }
    199
    200    /**
    201     * Generates a random integer within the specified range.
    202     *
    203     * @param startInclusive the smallest value that can be returned, must be non-negative
    204     * @param endExclusive   the upper bound (not included)
    205     * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is
    206     *                                  negative
    207     * @return the random integer
    208     * @deprecated Use {@link #secure()}, {@link #secureStrong()},or {@link #insecure()}.
    209     */
    210    @Deprecated
    211    public static int nextInt(final int startInclusive, final int endExclusive) {
    212        return secure().randomInt(startInclusive, endExclusive);
    213    }
    214
    215    /**
    216     * Generates a random long between 0 (inclusive) and Long.MAX_VALUE (exclusive).
    217     *
    218     * @return the random long
    219     * @see #nextLong(long, long)
    220     * @since 3.5
    221     * @deprecated Use {@link #secure()}, {@link #secureStrong()},or {@link #insecure()}.
    222     */
    223    @Deprecated
    224    public static long nextLong() {
    225        return secure().randomLong();
    226    }
    227
    228    /**
    229     * Generates a random long within the specified range.
    230     *
    231     * @param startInclusive the smallest value that can be returned, must be non-negative
    232     * @param endExclusive   the upper bound (not included)
    233     * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is
    234     *                                  negative
    235     * @return the random long
    236     * @deprecated Use {@link #secure()}, {@link #secureStrong()},or {@link #insecure()}.
    237     */
    238    @Deprecated
    239    public static long nextLong(final long startInclusive, final long endExclusive) {
    240        return secure().randomLong(startInclusive, endExclusive);
    241    }
    242
    243    /**
    244     * Gets the singleton instance based on {@link SecureRandom#SecureRandom()} which uses an algorithms/providers
    245     * specified in the {@code securerandom.strongAlgorithms} {@link Security} property.
    246     * <p>
    247     * The method {@link SecureRandom#SecureRandom()} is called on-demand.
    248     * </p>
    249     *
    250     * @return the singleton instance based on {@link SecureRandom#SecureRandom()}.
    251     * @see SecureRandom#SecureRandom()
    252     * @since 3.16.0
    253     */
    254    public static RandomUtils secure() {
    255        return SECURE;
    256    }
    257
    258    static SecureRandom secureRandom() {
    259        return SECURE_RANDOM_STRONG.get();
    260    }
    261
    262    /**
    263     * Gets the singleton instance based on {@link SecureRandom#getInstanceStrong()} which uses an algorithms/providers
    264     * specified in the {@code securerandom.strongAlgorithms} {@link Security} property.
    265     * <p>
    266     * The method {@link SecureRandom#getInstanceStrong()} is called on-demand.
    267     * </p>
    268     *
    269     * @return the singleton instance based on {@link SecureRandom#getInstanceStrong()}.
    270     * @see SecureRandom#getInstanceStrong()
    271     * @since 3.17.0
    272     */
    273    public static RandomUtils secureStrong() {
    274        return SECURE_STRONG;
    275    }
    276
    277    private final Supplier<Random> random;
    278
    279    /**
    280     * {@link RandomUtils} instances should NOT be constructed in standard programming. Instead, the class should be
    281     * used as {@code RandomUtils.nextBytes(5);}.
    282     * <p>
    283     * This constructor is public to permit tools that require a JavaBean instance to operate.
    284     * </p>
    285     *
    286     * @deprecated TODO Make private in 4.0.
    287     */
    288    @Deprecated
    289    public RandomUtils() {
    290        this(SECURE_STRONG_SUPPLIER);
    291    }
    292
    293    private RandomUtils(final Supplier<Random> random) {
    294        this.random = random;
    295    }
    296
    297    Random random() {
    298        return random.get();
    299    }
    300
    301    /**
    302     * Generates a random boolean value.
    303     *
    304     * @return the random boolean
    305     * @since 3.16.0
    306     */
    307    public boolean randomBoolean() {
    308        return random().nextBoolean();
    309    }
    310
    311    /**
    312     * Generates an array of random bytes.
    313     *
    314     * @param count the size of the returned array
    315     * @return the random byte array
    316     * @throws IllegalArgumentException if {@code count} is negative
    317     * @since 3.16.0
    318     */
    319    public byte[] randomBytes(final int count) {
    320        Validate.isTrue(count >= 0, "Count cannot be negative.");
    321        final byte[] result = new byte[count];
    322        random().nextBytes(result);
    323        return result;
    324    }
    325
    326    /**
    327     * Generates a random double between 0 (inclusive) and Double.MAX_VALUE (exclusive).
    328     *
    329     * @return the random double
    330     * @see #randomDouble(double, double)
    331     * @since 3.16.0
    332     */
    333    public double randomDouble() {
    334        return randomDouble(0, Double.MAX_VALUE);
    335    }
    336
    337    /**
    338     * Generates a random double within the specified range.
    339     *
    340     * @param startInclusive the smallest value that can be returned, must be non-negative
    341     * @param endExclusive   the upper bound (not included)
    342     * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is
    343     *                                  negative
    344     * @return the random double
    345     * @since 3.16.0
    346     */
    347    public double randomDouble(final double startInclusive, final double endExclusive) {
    348        Validate.isTrue(endExclusive >= startInclusive, "Start value must be smaller or equal to end value.");
    349        Validate.isTrue(startInclusive >= 0, "Both range values must be non-negative.");
    350        if (startInclusive == endExclusive) {
    351            return startInclusive;
    352        }
    353        return startInclusive + (endExclusive - startInclusive) * random().nextDouble();
    354    }
    355
    356    /**
    357     * Generates a random float between 0 (inclusive) and Float.MAX_VALUE (exclusive).
    358     *
    359     * @return the random float
    360     * @see #randomFloat(float, float)
    361     * @since 3.16.0
    362     */
    363    public float randomFloat() {
    364        return randomFloat(0, Float.MAX_VALUE);
    365    }
    366
    367    /**
    368     * Generates a random float within the specified range.
    369     *
    370     * @param startInclusive the smallest value that can be returned, must be non-negative
    371     * @param endExclusive   the upper bound (not included)
    372     * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is
    373     *                                  negative
    374     * @return the random float
    375     */
    376    public float randomFloat(final float startInclusive, final float endExclusive) {
    377        Validate.isTrue(endExclusive >= startInclusive, "Start value must be smaller or equal to end value.");
    378        Validate.isTrue(startInclusive >= 0, "Both range values must be non-negative.");
    379        if (startInclusive == endExclusive) {
    380            return startInclusive;
    381        }
    382        return startInclusive + (endExclusive - startInclusive) * random().nextFloat();
    383    }
    384
    385    /**
    386     * Generates a random int between 0 (inclusive) and Integer.MAX_VALUE (exclusive).
    387     *
    388     * @return the random integer
    389     * @see #randomInt(int, int)
    390     * @since 3.16.0
    391     */
    392    public int randomInt() {
    393        return randomInt(0, Integer.MAX_VALUE);
    394    }
    395
    396    /**
    397     * Generates a random integer within the specified range.
    398     *
    399     * @param startInclusive the smallest value that can be returned, must be non-negative
    400     * @param endExclusive   the upper bound (not included)
    401     * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is
    402     *                                  negative
    403     * @return the random integer
    404     * @since 3.16.0
    405     */
    406    public int randomInt(final int startInclusive, final int endExclusive) {
    407        Validate.isTrue(endExclusive >= startInclusive, "Start value must be smaller or equal to end value.");
    408        Validate.isTrue(startInclusive >= 0, "Both range values must be non-negative.");
    409        if (startInclusive == endExclusive) {
    410            return startInclusive;
    411        }
    412        return startInclusive + random().nextInt(endExclusive - startInclusive);
    413    }
    414
    415    /**
    416     * Generates a random long between 0 (inclusive) and Long.MAX_VALUE (exclusive).
    417     *
    418     * @return the random long
    419     * @see #randomLong(long, long)
    420     * @since 3.16.0
    421     */
    422    public long randomLong() {
    423        return randomLong(Long.MAX_VALUE);
    424    }
    425
    426    /**
    427     * Generates a {@code long} value between 0 (inclusive) and the specified value (exclusive).
    428     *
    429     * @param n Bound on the random number to be returned. Must be positive.
    430     * @return a random {@code long} value between 0 (inclusive) and {@code n} (exclusive).
    431     */
    432    private long randomLong(final long n) {
    433        // Extracted from o.a.c.rng.core.BaseProvider.nextLong(long)
    434        long bits;
    435        long val;
    436        do {
    437            bits = random().nextLong() >>> 1;
    438            val = bits % n;
    439        } while (bits - val + n - 1 < 0);
    440        return val;
    441    }
    442
    443    /**
    444     * Generates a random long within the specified range.
    445     *
    446     * @param startInclusive the smallest value that can be returned, must be non-negative
    447     * @param endExclusive   the upper bound (not included)
    448     * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is
    449     *                                  negative
    450     * @return the random long
    451     * @since 3.16.0
    452     */
    453    public long randomLong(final long startInclusive, final long endExclusive) {
    454        Validate.isTrue(endExclusive >= startInclusive, "Start value must be smaller or equal to end value.");
    455        Validate.isTrue(startInclusive >= 0, "Both range values must be non-negative.");
    456        if (startInclusive == endExclusive) {
    457            return startInclusive;
    458        }
    459        return startInclusive + randomLong(endExclusive - startInclusive);
    460    }
    461
    462    @Override
    463    public String toString() {
    464        return "RandomUtils [random=" + random() + "]";
    465    }
    466
    467}