Java provides multiple ways to generate random numbers through different built-in methods and classes like `java.util.Random` and `java.lang.Math`.

In this article, we shall look at three different ways to generate random numbers in Java. You'll also learn how to restrict the random number generation in a specific range.

## Java 8 Random Number Generation

Java 8 introduced a new method, `ints()`, as a part of the `java.util.Random` class. This method returns an unlimited stream of pseudorandom integer values. You can restrict the random numbers between a specific range by providing the minimum and maximum values as arguments.

The following example demonstrates how you can use the `Random.ints()` method to generate a random integer value:

``````// create an instance of `Random`
Random random = new Random();

// generate randome integer value
int num = random.ints().findFirst().getAsInt();

// print random number
System.out.println("Random Number: " + num);
``````

The above code will output the following:

``````Random Number: -276754611
``````

Since we didn't set the random number bounds, `Random.ints()` will generate a random integer within `Integer.MIN_VALUE` and `Integer.MAX_VALUE`. However, you can limit the random number generation within a specific range as shown below:

``````// create an instance of `Random`
Random random = new Random();

// generate random integer value
// within 100 inclusive and 500 exclusive
int num = random.ints(100, 500).findFirst().getAsInt();

// print random number
System.out.println("Random Number [range 100-500]: " + num);
``````

Here is the output of the above code snippet:

``````Random Number [range 100-500]: 455
``````

By default, the `ints()` method generates a stream of unlimited pseudorandom numbers up to `Long.MAX_VALUE` size. To limit the size of the stream, you can do the following:

``````// create an instance of `Random`
Random random = new Random();

// generate 5 randome integers
random.ints(5).forEach(System.out::println);
``````

The above code generates 5 random integer values and prints them on the console. Here is how the output should look like:

``````261853113
-937163633
-2004940360
1260887368
193523502
``````

As you can see above, the random numbers are generated within the default range. To specify the range and size of the stream, you can do the following:

``````// create an instance of `Random`
Random random = new Random();

// generate 5 random integers
// within 10 inclusive and 100 exclusive
random.ints(5, 10, 100).forEach(System.out::println);
``````

The above code generates random integers between 10 (inclusive) and 100 (exclusive), with a stream size of 5. Finally, it prints out values using forEach() method.

Here is what the output looks like now:

``````32
78
63
67
33
``````

In addition to `Random.ints()`, Java 8 also introduced `Random.doubles()` and `Random.longs()` methods for pseudorandom double and long values generation. These methods accept the same parameters as `ints()`.

Here is an example that shows how you can generate a stream of random double and long values:

``````// create an instance of `Random`
Random random = new Random();

// generate 5 random long values
// within 100 inclusive and 1000 exclusive
System.out.println("Random Long Values");
System.out.println("------------------");
random.longs(5, 100, 1000).forEach(System.out::println);

// print an empty line
System.out.println();

// generate 5 randome double values
// within 7.99 inclusive and 49.58 exclusive
System.out.println("Random Double Values");
System.out.println("--------------------");
random.doubles(5, 7.99, 49.58).forEach(System.out::println);
``````

The above code snippet will print the following on the console:

``````Random Long Values
------------------
773
472
749
149
422

Random Double Values
--------------------
43.9940252755332
18.36065220679901
47.97256897484375
33.21094500155469
28.668240009603416
``````

## Using `Random` Class

In Java 7 and below, you can use the `java.util.Random` class to generate random numbers of different types, such as integers, double, floats, longs, and booleans.

To generate random numbers, all you need to do is create an instance of the `Random` class and then call one of the random value generator methods, such as `nextInt()`, `nextLong()`, or `nextDouble()`.

You can also pass an optional argument to the above methods to set an upper bound on the range of the numbers generated. Here is an example that shows how you can use the `Random` class to generate random integer, long, and double values:

``````// create an instance of `Random`
Random random = new Random();

// generate random integers
System.out.println("Random Integer: " + random.nextInt());
System.out.println("Random Integer [range 0-100]: " + random.nextInt(100));

// generate random longs
System.out.println("Random Long: " + random.nextLong());

// generate random doubles
System.out.println("Random Double: " + random.nextDouble());

// generate random floats
System.out.println("Random Float: " + random.nextFloat());
``````

The above code will output something like the below:

``````Random Integer: -798093346
Random Integer [range 0-100]: 16
Random Long: -6661017962932808427
Random Double: 0.9737058318011228
Random Float: 0.9319658
``````

As you can see above, the `nextInt()` method allows us to specify an upper bound of the generated random numbers. Another important thing to notice is both `nextFloat()` and `nextDouble()` methods only generate random float and double values between 0.0 and 1.0.

By default, `nextInt()` generates a random integer between 0 (inclusive) and 2 to the power of 32. If you want to use a custom range, you have to write the additional code. Here is an example that generates a random integer between 10 (inclusive) and 50 (exclusive):

``````// create an instance of `Random`
Random random = new Random();

// generate random integer
// range 10 (inclusive) and 50 (exclusive)
int num = random.nextInt(50) + 10;

// print random integer
System.out.println("Random Integer [range 10-50]: " + num);
``````

Here is what the output looks like:

``````Random Integer [range 10-50]: 48
``````

## Using `Math` Class

The `java.lang.Math` class provides various static methods for performing different numeric operations, such as calculating exponentiation, logarithms, and more.

One such method is `Math.random()`, which generates a double value with a positive sign greater than or equal to 0.0 and less than 1.0. The returned values are chosen pseudorandomly with (approximately) uniform distribution from that range.

Here is an example:

``````// create a random double
double num = Math.random();

// print random value
System.out.println("Random Double [range 0-1]: " + num);
``````

You should see an output like the one below for the above code snippet:

``````Random Double [range 0-1]: 0.10691196575437478
``````

To generate a random integer within a custom range using the `Math.random()` static method, you need to perform some manual calculations:

``````// create a random integer
// range between 20 (inclusive) and 50 (inclusive)
int num = Double.valueOf(Math.random() * ((50 - 20) + 1)).intValue() + 20;

// print random value
System.out.println("Random Integer [range 20-50]: " + num);
``````

The above code will output the following:

``````Random Integer [range 20-50]: 25
``````