In this article, you will learn about various options,
- how to declare and initialize arrays in Java,
- how to fill them with values,
- how to copy them,
- and how to convert collections and streams into arrays.
You will also learn about the unique features of multidimensional arrays in Java.
Declaring and Initializing Arrays in Java
We start with the most common operations, the array declaration and array initialization.
How to Declare an Array in Java
Declaring a variable is the time we make the variable and its type known to the compiler. The following two lines show the declaration of an int array and a string array:
int[] intArray;
String[] stringArray;
Code language: Java (java)
We do not yet specify the size of the array in the declaration. The array variables (in the example intArray
and stringArray
) do not contain the array itself but a reference to an array, which is ultimately an object on the Java heap. Only when we create the actual array object, we must define its size.
In the array declaration, the square brackets can also be placed after the variable name:
int intArray[];
String stringArray[];
Code language: Java (java)
This style was adopted from the C programming language. However, all Java style guides prefer the style shown first, i.e., with the brackets after the type and before the name.
How to Initialize a Java Array With Values
We can also initialize an array with values when declaring it. The following line of code shows how we can initialize an int array:
int[] winningNumbers = new int[]{14, 17, 29, 32, 45, 1, 2};
Code language: Java (java)
And this is how we can initialize a string array, for example:
String[] fruits = new String[]{"cherry", "papaya", "huckleberry"};
Code language: Java (java)
As the variable type (int
or String
) is repeated in the assignment in the previous two examples, we can also replace the preceding type with var
:
var winningNumbers = new int[]{14, 17, 29, 32, 45, 1, 2};
var fruits = new String[]{"cherry", "papaya", "huckleberry"};
Code language: Java (java)
Alternatively, we can also omit the new
keyword and the second type specification, but then the first type specification must remain and must not be replaced by var
:
int[] winningNumbers = {14, 17, 29, 32, 45, 1, 2};
String[] fruits = {"cherry", "papaya", "huckleberry"};
Code language: Java (java)
The square brackets may also be placed after the variable name in C style for the combined declaration and initialization:
int winningNumbers[] = {14, 17, 29, 32, 45, 1, 2};
String fruits[] = {"cherry", "papaya", "huckleberry"};
Code language: Java (java)
Separate Array Declaration and Initialization
You can also create an array with given array elements after the declaration:
int[] winningNumbers;
// . . .
winningNumbers = new int[]{14, 17, 29, 32, 45, 1, 2};
String[] fruits;
// . . .
fruits = new String[]{"cherry", "papaya", "huckleberry"};
Code language: Java (java)
However, this is only possible with the new
keyword. The variant without new
is only permitted for the combined declaration and initialization shown in the previous section.
How to Initialize an Empty Array in Java
In all previous examples, we specified concrete values the array should contain.
Instead of defining an array with specific values, we can also initialize an array by specifying a size (see also the article Array Length in Java), e.g., an array with ten int
elements:
int[] intArray = new int[10];
Code language: Java (java)
The instruction new int[10]
creates a new int
array with 10 elements. All elements are set to the default value 0. The command has the same effect as the following:
int[] intArray = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
Code language: Java (java)
We could also separate this type of initialization from the declaration:
int[] intArray;
// . . .
intArray = new int[10];
Code language: Java (java)
The various array types have the following default values:
- The default value for the integers
byte
,short
,int
, andlong
is 0. - The default value for the floating point numbers
float
anddouble
is 0.0. - For
char
, the default value is the Unicode character “NULL” (U+0000). - For all object arrays, the default is
null
.
Filling an Array With Values
Once we have created an array (in any of the ways shown above), we can fill it with values in various ways.
Setting Individual Array Elements
For example, if we have created an int
array, we can fill it element by element, e.g., with the square of the respective index:
int[] intArray = new int[11];
for (int i = 0; i < intArray.length; i++) {
intArray[i] = i * i;
}
Code language: Java (java)
This array then has the following content:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
Code language: plaintext (plaintext)
Setting All Array Elements to the Same Value: Arrays.fill()
We can fill an array with uniform values using the Arrays.fill()
method. The following code sets each element of the array to 99:
int[] intArray = new int[10];
Arrays.fill(intArray, 99);
Code language: Java (java)
This array then looks as follows:
[99, 99, 99, 99, 99, 99, 99, 99, 99, 99]
Code language: plaintext (plaintext)
There is a second, overloaded fill()
method with additional parameters that we can use to define the area to be filled. The following code, for example, fills the first five fields with 11 and the last five fields with 77:
int[] intArray = new int[10];
Arrays.fill(intArray, 0, 5, 11);
Arrays.fill(intArray, 5, 10, 77);
Code language: Java (java)
This array then looks as follows:
[11, 11, 11, 11, 11, 77, 77, 77, 77, 77]
Code language: plaintext (plaintext)
Filling an Array With Calculated Values: Arrays.setAll()
In the “Setting individual array elements” section, I showed you code that fills an array with square numbers using a loop.
We can also program this more simply using the Arrays.setAll()
method. We pass the array and a lambda function to this method, which calculates the value of a field based on its index:
int[] intArray = new int[11];
Arrays.setAll(intArray, i -> i * i);
Code language: Java (java)
The use of setAll()
makes it particularly easy to parallelize processing. All we have to do is replace setAll()
with parallelSetAll()
:
int[] intArray = new int[11];
Arrays.parallelSetAll(intArray, i -> i * i);
Code language: Java (java)
Internally, the method uses a parallel stream and, therefore, the common ForkJoinPool. As the calculation method is stateless, the performance can scale almost linearly with the number of CPU cores.
How to Copy a Java Array
There are various methods in Java for copying an existing array.
Copying Primitive Arrays With clone()
The simplest way to copy an array is the clone()
method:
int[] intArray = {6, 11, 5, 7, 44, 7, 4};
int[] copy = intArray.clone();
Code language: Java (java)
This code creates a second array that can be changed independently of the first array. We can now change values in both arrays:
intArray[1] = 999;
copy[2] = 88;
Code language: Java (java)
The consequence is that both arrays have different contents:
intArray: [6, 999, 5, 7, 44, 7, 4]
copy: [6, 11, 88, 7, 44, 7, 4]
Code language: plaintext (plaintext)
Graphically, you can imagine this as follows (this is merely a symbolic representation that only reflects the content of the arrays – arrays also have an internal object header and a field that stores their size):
The situation is different with object arrays, as we will see in the next section.
Copying Object Arrays With clone()
When working with an object array, we must note that only the references to the objects are copied, not the objects themselves.
In the following example, we copy an array of StringBuilder
objects, then change the values of a StringBuilder
object in the first array and output both arrays:
StringBuilder[] fruits = {
new StringBuilder("cherry"),
new StringBuilder("papaya"),
new StringBuilder("huckleberry")
};
StringBuilder[] copy = fruits.clone();
fruits[1].reverse();
System.out.println("fruits: " + Arrays.toString(fruits));
System.out.println("copy: " + Arrays.toString(copy));
Code language: Java (java)
In the output, you will see the reversed word “ayapap” in the middle position in both arrays. That is because not the StringBuilder
object has been copied but only a pointer. That means that both arrays contain a pointer to the same StringBuilder
object:
If you want to change an object in just one array, you must replace it by assigning a new object, e.g., a new StringBuilder
. Let’s append the following lines to the code from above:
copy[2] = new StringBuilder("tomato");
System.out.println("fruits: " + Arrays.toString(fruits));
System.out.println("copy: " + Arrays.toString(copy));
Code language: Java (java)
You will then see the following output – tomato
is now located exclusively in the cloned array:
fruits: [cherry, ayapap, huckleberry]
copy: [cherry, ayapap, tomato]
Code language: plaintext (plaintext)
Graphically, you can imagine this as follows:
The StringBuilder
with the contents “cherry” and “ayapap” are referenced by both arrays, the StringBuilder
with the content “huckleberry” is only referenced by the fruits
array, and the StringBuilder
with the content “tomato” is only referenced by the copy
array.
System.arraycopy()
Sometimes, we do not want to copy the entire array, but only a part of it. We can use the low-level method System.arraycopy()
to help us with this.
Let’s assume we want to copy the middle three winning numbers into another array. Then, we first create a target array of size three:
int[] winningNumbers = {14, 17, 29, 32, 45, 1, 2};
int[] middleThree = new int[3];
Code language: Java (java)
Then we call up System.arraycopy()
as follows and print the result:
System.arraycopy(winningNumbers, 2, middleThree, 0, 3);
Code language: Java (java)
The method has the following parameters:
- Source array
- Start position in the source array
- Target array
- Start position in the target array
- Number of elements to copy
The following graphic shows the meanings of the parameters once again:
We can now print the result of the copying process:
System.out.println("middleThree: " + Arrays.toString(middleThree));
Code language: Java (java)
And we should see the following output, matching the graphic above:
middleThree: [29, 32, 45]
Code language: plaintext (plaintext)
Arrays.copyOf()
Dealing with System.arraycopy()
is tedious. For this reason, the class java.util.Arrays
contains some auxiliary methods that make copying easier.
We can use the Arrays.copyOf()
method to copy the entire array or parts of the array. The following code copies the complete array:
int[] winningNumbers = {14, 17, 29, 32, 45, 1, 2};
int[] copy = Arrays.copyOf(winningNumbers, winningNumbers.length);
System.out.println("copy = " + Arrays.toString(copy));
Code language: Java (java)
The second parameter specifies the desired length of the target array. If you look at the source code of the method Arrays.copyOf()
, you will see that it simply invokes clone()
if the second parameter is equal to the length of the source array.
If you specify a shorter length as the second parameter, the copy is correspondingly shorter than the original:
int[] firstThree = Arrays.copyOf(winningNumbers, 3);
System.out.println("firstThree = " + Arrays.toString(firstThree));
Code language: Java (java)
This code prints the following – the target array thus contains the first three numbers of the source array:
firstThree = [14, 17, 29]
Code language: plaintext (plaintext)
In the source code of Arrays.copyOf()
, you will see that in this case, a new array of the desired size is first created, and then the desired elements are copied from the source array into the target array using System.arraycopy()
.
You can also specify a value that is greater than the length of the source array:
int[] longerArray = Arrays.copyOf(winningNumbers, 10);
System.out.println("longerArray = " + Arrays.toString(longerArray));
Code language: Java (java)
In this case, the remaining fields of the target array will be filled with default values (i.e., zeros), and you will get the following result:
longerArray = [14, 17, 29, 32, 45, 1, 2, 0, 0, 0]
Code language: plaintext (plaintext)
Arrays.copyOfRange()
To copy a part further back from the array, we can use Arrays.copyOfRange()
. The following code copies the middle three elements, as we did above with System.arraycopy()
:
int[] winningNumbers = {14, 17, 29, 32, 45, 1, 2};
int[] middleThree = Arrays.copyOfRange(winningNumbers, 2, 5);
System.out.println("middleThree = " + Arrays.toString(middleThree));
Code language: Java (java)
In addition to the source array, enter the start and end position (not the length!) of the range to be copied as parameters.
If you look at the source code of copyOfRange()
, you will see that this method also uses clone()
and System.arraycopy()
.
Creating Arrays From Other Data Structures
If you have data in a collection, such as a list or a set, you can copy it into an array using the toArray()
method.
How to Convert a List to an Array: List.toArray()
The following example shows four ways in which you can convert a string list into a string array:
List<String> fruits = List.of("honeydew", "dragonfruit", "boysenberry");
Object[] array1 = fruits.toArray();
String[] array2 = fruits.toArray(new String[fruits.size()]);
String[] array3 = fruits.toArray(new String[0]);
String[] array4 = fruits.toArray(String[]::new);
Code language: Java (java)
In the first variant without parameters, the return value is an Object
array. That is because collections such as lists and sets do not contain any type information at runtime due to so-called type erasure and can, therefore, contain any objects from the JVM’s point of view.
In the second variant, we pass a new array of the desired type with the required size. The toArray()
method then copies the list elements into this array.
In the third variant, we pass a new array of the desired type with a length of 0. The toArray()
method then creates a new array of the required size and copies the elements into this array.
In the fourth method, we pass a reference to the array constructor. The Collection.toArray()
method calls this constructor with the parameter 0, i.e., creates an array of length 0 and then invokes the third method.
Aleksey Shipilёv compared the performance of the different variants of Collection.toArray()
on his blog and concluded that the first variant, i.e., the one that returns an Object
array, is the fastest. Of the variants that return an array of the target type, variants three and four are the fastest. This is counter-intuitive, as two arrays are created (first one of length 0, then one of the required length). You can read why passing an array of length 0 is nevertheless faster than passing an array of the appropriate size in the article linked above.
The second variant can also lead to a race condition: With a thread-safe collection, if another thread changes its size after calling size()
and before calling toArray()
, toArray()
would return an array with the old length instead of the new one – the array would thus be truncated or padded with zeros.
I always recommend using the fourth variant, i.e., the one with the constructor parameter, as this could be optimized in the future.
How to Convert a Set to an Array: Set.toArray()
You can use the toArray()
calls shown above unchanged to convert a Set
into an array:
Set<String> fruits = Set.of("honeydew", "dragonfruit", "boysenberry");
Object[] array1 = fruits.toArray();
String[] array2 = fruits.toArray(new String[fruits.size()]);
String[] array3 = fruits.toArray(new String[0]);
String[] array4 = fruits.toArray(String[]::new);
Code language: Java (java)
If the set has a defined iteration sequence (such as a TreeSet
), then the Set.toArray()
methods guarantee that the elements are copied into the array in iteration sequence.
Here, too, my recommendation is always to use the fourth variant.
Creating an Array From an Object Stream
Not only collections but also streams have toArray()
methods. We start, analogous to the collections, with the generic object streams. The following code shows two variants of converting a string stream into an array. Note that a stream can only be consumed once, meaning it can also only be transformed into an array once – therefore, for this example, we have to create two streams:
Stream<String> stream1 = Stream.of("mango", "tomato", "coconut");
Object[] objects = stream1.toArray();
Stream<String> stream2 = Stream.of("cherry", "date", "raspberry");
String[] strings = stream2.toArray(String[]::new);
Code language: Java (java)
There are only two variants here, namely those that we have already seen in the collections as variant 1 and variant 4:
- a variant without type specification that returns only an object array,
- and a variant with a constructor reference for the desired array type.
A variant to which we can pass an array of the desired type does not exist for streams. That aligns with my recommendation not to use variants 2 and 3 for collections. So why are these variants available for collections? For historical reasons: When the Collections Framework was introduced in Java 1.2 in 1998, there were no method references as required for passing the constructor in variant 4.
Creating an Array From a Primitive Stream
In contrast to collections, there are also primitive variants of streams, namely IntStream
, LongStream
, and DoubleStream
. Primitive streams only offer a single toArray()
method. As the type is always known here, it is unnecessary to specify it.
The following code creates an int
array with the values 1 to 10, a long
array with a sequence of numbers that starts at 1 and doubles as long as the value remains below 2,000, and a double
array with a sequence of numbers that starts at 1.0 and is halved until a total of eight elements have been created:
int[] intArray = IntStream.rangeClosed(1, 10).toArray();
long[] longArray = LongStream.iterate(1, x -> x < 2000, x -> x * 2).toArray();
double[] doubleArray = DoubleStream.iterate(1.0, x -> x / 2.0).limit(8).toArray();
System.out.println("intArray = " + Arrays.toString(intArray));
System.out.println("longArray = " + Arrays.toString(longArray));
System.out.println("doubleArray = " + Arrays.toString(doubleArray));
Code language: Java (java)
The code prints the following arrays:
intArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
longArray = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024]
doubleArray = [1.0, 0.5, 0.25, 0.125, 0.0625, 0.03125, 0.015625, 0.0078125]
Code language: plaintext (plaintext)
Declaring and Initializing 2D Arrays in Java
Multidimensional arrays in Java are not really multidimensional but arrays of arrays. In the following sections, I will show you precisely what this means and how these arrays are declared and initialized using the example of two-dimensional arrays.
How to Declare a 2D Array in Java
You declare a two-dimensional array as follows:
int[][] intMatrix;
String[][] stringMatrix;
Code language: Java (java)
Just as with one-dimensional arrays, we do not specify a size in the declaration. Also, with multidimensional arrays, we can write the brackets in C style after the variable name:
int intMatrix[][];
String stringMatrix[][];
Code language: Java (java)
As with one-dimensional arrays, all Java style guides prefer the first variant.
How to Initialize a 2D Array in Java
A two-dimensional array can be initialized directly in the declaration – with new
followed by the type and two pairs of square brackets:
int[][] intMatrix = new int[][]{{2, 3, 6}, {4, 5, 1}};
Code language: Java (java)
If we use new
, we may also write var
at the beginning:
var intMatrix = new int[][]{{2, 3, 6}, {4, 5, 1}};
Code language: Java (java)
Or we leave out new
and the second type specification, and then we are not allowed to use var
. This is the shortest option:
int[][] intMatrix = {{2, 3, 6}, {4, 5, 1}};
Code language: Java (java)
Of course, we can also split the declaration and initialization into two lines, but then we have to specify the type in both lines explicitly:
int[][] intMatrix;
intMatrix = new int[][]{{2, 3, 6}, {4, 5, 1}};
Code language: Java (java)
We can also create an empty array (more precisely, one that contains only zeros) and then fill the fields in a second step:
int[][] intMatrix = new int[2][3];
intMatrix[0][0] = 2;
intMatrix[0][1] = 3;
intMatrix[0][2] = 6;
intMatrix[1][0] = 4;
intMatrix[1][1] = 5;
intMatrix[1][2] = 1;
Code language: Java (java)
It is important to know that in Java, a two-dimensional array is actually an array of arrays. The example arrays that we have created in this section are stored in memory as follows (the illustration again dispenses with the object header and the length field):
Each row of the matrix is a separate array. You can also access these arrays, e.g., print them as follows:
int[] row0 = intMatrix[0];
int[] row1 = intMatrix[1];
System.out.println("row0 = " + Arrays.toString(row0));
System.out.println("row1 = " + Arrays.toString(row1));
Code language: Java (java)
We could also create the intMatrix
array as follows:
int[][] intMatrix = new int[2][3];
intMatrix[0] = new int[]{2, 3, 6};
intMatrix[1] = new int[]{4, 5, 1};
Code language: Java (java)
The sub-arrays intMatrix[0]
and intMatrix[1]
are initially set to {0, 0, 0}
in the first line and then overwritten by new arrays in the second and third lines.
We can also omit the size specification for the second dimension in the first line:
int[][] intMatrix = new int[2][]; // ⟵ without second dimension length
intMatrix[0] = new int[]{2, 3, 6};
intMatrix[1] = new int[]{4, 5, 1};
Code language: Java (java)
In this case, intMatrix[0]
and intMatrix[1]
are each initially null
.
Incidentally, it is not mandatory for all sub-arrays to be the same length. The following is also permitted:
int[][] intMatrix = new int[2][];
intMatrix[0] = new int[]{2, 3, 6};
intMatrix[1] = new int[]{4, 5, 1, 9, 7};
Code language: Java (java)
And we can write that too:
int[][] intMatrix = {{2, 3, 6}, {4, 5, 1, 9, 7}};
Code language: Java (java)
The 2D arrays created in the last two examples can be visualized as follows:
The methods discussed in the previous sections – Arrays.fill()
, Arrays.setAll()
, clone()
, System.arraycopy()
, Arrays.copyOf()
, and Arrays.copyOfRange()
– can be applied to both levels of such a nested array.
The following code, for example, generates a matrix with the products of the multiplication tables:
int[][] products = new int[11][11];
for (int i = 0; i < 11; i++) {
int finalI = i; // ⟵ we need an effectively final variable for the lambda
Arrays.setAll(products[i], j -> finalI * j);
}
Code language: Java (java)
The following code sets all rows of a two-dimensional matrix to an array with the values one to four:
int[][] matrix = new int[3][];
Arrays.fill(matrix, new int[]{1, 2, 3, 4});
Code language: Java (java)
Note, however, that we have only created this inner array once and that all rows refer to the same inner array:
If you execute the following code, you will see that the supposed change to a single field in the matrix has changed an entire column:
matrix[1][1] = 99;
System.out.println("matrix = " + Arrays.deepToString(matrix));
Code language: Java (java)
To create a separate array for each line, you can use Arrays.setAll()
, as the lambda passed in the second parameter is called for each line:
Arrays.setAll(matrix, ignored -> new int[]{1, 2, 3, 4});
Code language: Java (java)
It is good to know these unique features of multidimensional arrays in Java.
Conclusion
In this article, you have learned about various methods for creating arrays in Java – from initialization with static values or default values to filling an array with Arrays.fill()
or Arrays.setAll()
and copying arrays with clone()
, System.arrayCopy()
and Arrays.copyOf()
through to conversion from existing data structures such as lists, sets and streams.
You are now also familiar with the characteristics of multidimensional arrays in Java and know what to look out for when using them.
If you liked the article, share it using one of the share buttons at the end or leave me a comment.
Would you like to know when new articles will be published on HappyCoders.eu? Then click here to sign up for the HappyCoders.eu newsletter.