Arrays in Java provide a way to store and manipulate collections of elements. They offer a structured approach to handling data, allowing developers to organize information efficiently.
Table of Contents
1. Anatomy of an Arrray
An array in Java is a contiguous block of memory that stores elements of the same data type. The elements can be primitive data types, objects, or even other arrays. The basic structure of an array can be visualized as follows:
+---+---+---+---+---+
| 0 | 1 | 2 | 3 | 4 |
+---+---+---+---+---+
| | | | |
[10, 20, 30, 40, 50]
- Index: Each element in the array is assigned a unique index, starting from 0 and incrementing by 1 for each subsequent element.
- Size: The total number of elements an array can hold is determined at the time of declaration and cannot be changed afterward.
- Initialization: Elements can be initialized individually or collectively using various syntaxes.
2. Creating an Array of Primitives
Arrays can be declared and initialized in several ways:
// Declaration with size
int[] numbers = new int[5];
// Initialization with values
int[] scores = new int[]{42, 66, 100};
// Anonymous array
int[] values = {10, 20, 30, 40, 50};
// [] after the name
int otherValues[] = {10, 20, 30, 40, 50};
Declaration with size
- Declaration: This line declares an array named
numbers
that can hold 5 integers. - Initialization: The
new int[5]
allocates memory for an array of integers with a size of 5. - Default Values: Since no explicit values are assigned, the elements of
numbers
are initialized to the default value of0
for integers.
Initialization with values
- Declaration: This line declares an array named
scores
that can hold integers. - Initialization: The
new int[]{42, 66, 100}
creates an array and initializes it with the specified values. - No Size Specified: The size of the array is inferred from the number of provided values.
Anonymous array
- Declaration and Initialization Combined: This line declares and initializes an array named
values
with the specified values. - Concise Syntax: The use of
{}
is a shorthand for creating an array without explicitly mentioning the keywordnew
and the data type. - No Size nor Type Specified: The size and type of the array is inferred from the provided values.
[] after the name
Alternate Syntax: In Java, both int[] numbers
and int numbers[]
are valid ways to declare an array. However, the former is more widely used and considered good practice.
3. Creating an Array with Reference Variables
In Java, arrays can hold elements of any type, including reference variables to objects. This flexibility allows developers to create arrays of user-defined classes or any built-in classes.
It is important to understand that array does not allocate space for the object itself. Instead, it allocates space for a reference to where the objects are really stored. For the example: String[] animals = {"lion", "pig", "dog"}
.
+-----------+
| animals |
+-----------+
| [0] | -----------------------------------------------------> "lion"
| [1] | -----------------------------------------------------> "pig"
| [2] | -----------------------------------------------------> "dog"
+-----------+
animals
is the array variable.- The array has three slots (
[0]
,[1]
, and[2]
), each capable of holding a reference. - Each slot in the array holds a reference to the corresponding
String
object (“lion”, “pig”, and “dog”).
3.1. Declaration and Initialization
String[] words; // Declaration (not yet instantiated)
- Declaration: The array is declared with a variable name. At this point, it doesn’t point to any memory location.
words = new String[2]; // Instantiation (allocates memory for two references)
- Initialization with default values: Memory is allocated for the number of references that are declared in the instantiation. However, each reference currently points to
null
.
String[] array1 = new String[]{"hello", "world"};
- Initialization with specific values: An array variable
array1
is declared and instantiated with an array of twoString
objects (“hello”, “world”). Memory is allocated for the array and the actualString
objects.
3.2. Casting
You can assign an array of a more specific type to an array of a more general type without the need for explicit casting. However, if you want to assign it back to the more specific type, you’ll need to use explicit casting.
String[] words = {"word"};
Object[] objects = words;
String[] words2 = (String[]) objects;
String[] words = {"word"};
:- Initializes an array of
String
with a single element.
- Initializes an array of
Object[] objects = words;
:- Assigns the
words
array (array ofString
) to an array ofObject
. - This is allowed because
Object
is more general thanString
.
- Assigns the
String[] words2 = (String[]) objects;
:- Explicitly casts the array of
Object
back to an array ofString
. - This casting is required because the original array was cast to a more general type (
Object[]
), and you need to explicitly tell the compiler that you’re treating it as an array ofString
again.
- Explicitly casts the array of
4. Using an Array
Arrays are fundamental data structures in Java that allow you to store and access multiple values of the same type.
String[] fruits = {"Apple", "Banana", "Orange"};
Arrays are zero-indexed, meaning the first element is at index 0, the second at index 1, and so on. To access elements, simply specify the index inside square brackets:
String firstFruit = fruits[0]; // Access the first element
String secondFruit = fruits[1]; // Access the second element
String thirdFruit = fruits[2]; // Access the third element
To determine the length of an array, you can use the length
property. Note that length
is not a method, so no parentheses are needed:
int arrayLength = fruits.length; // Get the length of the array
It’s important to highlight that array indices start at 0, but the length
property represents the total count of elements, starting from 1. This means that for our fruits
array, arrayLength
will be 3.
A common task is to iterate through the elements of an array. You can achieve this using a loop, such as a for
loop:
for (int i = 0; i < fruits.length; i++) {
System.out.println("Fruit at index " + i + ": " + fruits[i]);
}
In this example, the loop iterates from 0 to fruits.length - 1
, printing each element along with its index.
4.1. Sorting
Sorting is a common operation in programming, and Java provides convenient methods to sort arrays efficiently.
import java.util.Arrays;
public class ArraySortingExample {
public static void main(String[] args) {
int[] numbers = {42, 18, 127};
System.out.println("Before sorting: " + Arrays.toString(numbers));
Arrays.sort(numbers);
System.out.println("After sorting: " + Arrays.toString(numbers));
}
}
output:
Before sorting: [42, 18, 127]
After sorting: [18, 42, 127]
The result is a sorted array of numbers. Now lets have a look what happens when we use String types
String[] numbers = {"42", "18", "127"};
System.out.println("Before sorting: " + Arrays.toString(numbers));
Arrays.sort(numbers);
System.out.println("After sorting: " + Arrays.toString(numbers));
output:
Before sorting: [42, 18, 127]
After sorting: [127, 18, 42]
String sorts in alphabetic order: 1 sorts before 4 and 2 sorts before 8. It is possible to create custom sort orders using something called a comparator
4.2. Searching
Searching in Java becomes notably efficient when dealing with sorted arrays, and one of the most powerful algorithms for this purpose is the binary search.
Binary search relies on the assumption that the array is already sorted. It follows a “divide and conquer” approach, repeatedly dividing the search range in half until the target element is found or the search space is exhausted.
Here are the scenarios and results of binary search:
Scenario | Result |
---|---|
Target element found in sorted array | Index of the match |
Target element not found in sorted array | Negative value indicating one smaller than the negative of the index where a match needs to be inserted to preserve sorted order |
Unsorted array | The result is unpredictable |
examples:
int[] array = {70, 10, 30, 20, 50, 60, 80, 40, 90};
int[] sortedArray = {10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
// Using binary search
System.out.println(Arrays.binarySearch(sortedArray, 20)); // 1
System.out.println(Arrays.binarySearch(sortedArray, 10)); // 0
System.out.println(Arrays.binarySearch(sortedArray, 75)); // -8
System.out.println(Arrays.binarySearch(sortedArray, 35)); // -4
System.out.println(Arrays.binarySearch(sortedArray, 2)); // -1
System.out.println(Arrays.binarySearch(array, 20)); // Unpredictable result
System.out.println(Arrays.binarySearch(array, 35)); // Unpredictable result
Arrays.binarySearch(sortedArray, 20)
: The target element 20 is found at index 1. The output is1
.Arrays.binarySearch(sortedArray, 10)
: The target element 10 is found at index 0. The output is0
.Arrays.binarySearch(sortedArray, 75)
: The target element 75 is not found. The negative value-8
indicates the insertion point (one smaller than the negative of the index where a match needs to be inserted to preserve sorted order).Arrays.binarySearch(sortedArray, 35)
: The target element 35 is not found. The negative value-4
indicates the insertion point.Arrays.binarySearch(sortedArray, 2)
: The target element 2 is not found. The negative value-1
indicates the insertion point.Arrays.binarySearch(array, 20)
: The result is unpredictable because the array is not sorted.Arrays.binarySearch(array, 35)
: The result is unpredictable due to the unsorted array.
4.3. Comparing
4.3.1. compare()
The Arrays.compare()
method in Java returns different outcomes based on the comparison between two arrays. Here’s a breakdown of possible outcomes:
- Negative Value (-1):
- Indicates that the first non-equal element in the first array has a lower value than the corresponding element in the second array.
- Both arrays are the same, but the second array has extra elements at the end
- Zero (0):
- Both arrays are the same length and each corresponding pair of elements in both arrays are equal.
- Positive Value (1):
- Indicates that the first non-equal element in the first array has a higher value than the corresponding element in the second array.
- Both arrays are the same, but the first array has extra elements at the end
what does smaller mean:
- null is smaller than any other value
- for numbers, normal numeric order applies
- for strings/characters, numbers are smaller than letters
- for strings/characters, uppercase is smaller than lowercase
Here’s a table illustrating possible outcomes of comparing two arrays (array1
and array2
) using Arrays.compare()
:
array1 | array2 | Result | Reason |
---|---|---|---|
{1, 2, 3} | {1, 2, 3} | 0 | Both arrays are lexicographically equal. |
{1, 2, 3} | {1, 2, 4} | -1 | First non-equal element in array1 is smaller. |
{1, 2, 3} | {1, 2, 2} | 1 | First non-equal element in array1 is larger. |
{1, 2, 3} | {1, 2, 3, 4} | -1 | Both arrays are equal up to the length of array1. |
{1, 2, 3, 4} | {1, 2, 3} | 1 | Both arrays are equal up to the length of array2. |
4.3.2. mismatch()
The Arrays.mismatch()
method in Java is used to find the index of the first mismatch between two arrays. If the arrays are equal, it returns -1. Here are some examples to illustrate its usage:
import java.util.Arrays;
public class ArrayMismatchExample {
public static void main(String[] args) {
int[] array1 = {1, 2, 3, 4, 5};
int[] array2 = {1, 2, 3, 4, 5};
int mismatchIndex1 = Arrays.mismatch(array1, array2);
System.out.println("Mismatch Index 1: " + mismatchIndex1); // Output: -1
int[] array3 = {1, 2, 3, 4, 5};
int[] array4 = {1, 2, 3, 9, 5};
int mismatchIndex2 = Arrays.mismatch(array3, array4);
System.out.println("Mismatch Index 2: " + mismatchIndex2); // Output: 3
String[] words1 = {"apple", "banana", "orange"};
String[] words2 = {"apple", "banana", "grape"};
int mismatchIndex3 = Arrays.mismatch(words1, words2);
System.out.println("Mismatch Index 3: " + mismatchIndex3); // Output: 2
}
}
mismatchIndex1
is -1 becausearray1
andarray2
are equal.mismatchIndex2
is 3 because the arrays differ at index 3 (array3[3] != array4[3]
).mismatchIndex3
is 2 because the arrays differ at index 2 (words1[2] != words2[2]
).
4.3.3. Summary
Method | Used For | Outcome (Arrays are the same) | Outcome (Arrays are different) |
---|---|---|---|
equals() | Equality Comparison | true | false |
compare() | Numeric Comparison | 0 | Negative/Positive integer |
mismatch() | Element Mismatch | -1 | Index of first mismatch |
5. Multidimensional Arrays
Arrays are objects and array components can be objects. This means that arrays can hold others arrays. Such arrays are called multidimensional arrays.
There are different ways to declare a multidimensional array in Java:
int[][] multiArray; // brackets are placed after the type.
int multiArray2[][]; // brackets are placed after the variable name.
int[] multiArray3[]; // mixed style
All of the above are valid ways of declaring a 2D array, but the first two ways are preferred.
You can specify the size of a multidimensional array during initialization:
String[][] multiArr = new String[3][2];
The result is an array with three elements, each of which refers to an array of two elements. The addressable range can be visualized as [0][0]
through [2][1]
. The visiualization looks like this:
[ 1 | 2 | 3 ]
↓ ↓ ↓
[ 1 | 2 ] [ 3 | 4 ] [ 5 | 6 ]
Let’s print this array to the system:
String[][] multiArr = new String[3][2];
for(String[] arr : multiArr){
for (String word : arr){
System.out.print(word + " ");
}
System.out.println();
}
- The outer loop (
for(String[] arr : multiArr)
) iterates over each row (arr
) of the 2D array. - The inner loop (
for (String word : arr)
) iterates over each element (word
) in the current row. - Inside the inner loop, each word is printed, followed by a space.
After printing all the elements in a row, a newline character (System.out.println()
) is added to move to the next line, creating a visual separation between rows.
The output will be determined by the fact that the array was initialized but not populated with actual strings. In Java, uninitialized elements in an array of objects (like strings) are initialized to null
. Therefore, the output will consist of spaces for null elements:
null null
null null
null null
Now let’s set the first and the last elements of this 2D array:
multiArr[0][0] = "First Element";
multiArr[2][1] = "Last Element";
The visualization now looks like this:
[ 1 | 2 | 3 ]
↓ ↓ ↓
[ First Element | 2 ] [ 3 | 4 ] [ 5 | Last Element ]
If we print this to the system, the output looks like this:
First Element null
null null
null Last Element
A multidimensional array can contain arrays of different sizes. Let’s consider an example:
int[][] differentSizes={{5,6},{1},{1,2,3},{9,8,7,6}};
for(int[] inner : differentSizes){
for (int num : inner){
System.out.print(num + " ");
}
System.out.println();
}
the output is:
5 6
1
1 2 3
9 8 7 6
6. Converting between Array and List
6.1. From List to Array
Converting between an ArrayList and an array in Java involves using the toArray()
method provided by the List
interface. Additionally, the toArray(T[] a)
method can be used to specify the type of the resulting array explicitly.
import java.util.ArrayList;
import java.util.List;
public class ArrayListToArray {
public static void main(String[] args) {
List<String> stringList = new ArrayList<>();
stringList.add("One");
stringList.add("Two");
stringList.add("Three");
Object[] array1 = stringList.toArray();
String[] array2 = stringList.toArray(new String[0]);
stringList.clear();
System.out.println(stringList.size());
System.out.println(array1.length);
System.out.println(array2.length);
}
}
- The
toArray()
method, when called without arguments, returns an array of typeObject
. This means that the elements inarray1
are of typeObject
, and you would need to cast them to the appropriate type (in this case,String
) when accessing them. Since it’s of typeObject[]
, the array can store any type of object. - The
toArray(T[] a)
method allows you to specify the type of the resulting array explicitly. In this case,new String[0]
is passed as an argument, indicating that the resulting array should be of typeString[]
. This way, the elements inarray2
are directly of typeString
, and you don’t need to cast them. - When you call
clear()
on theArrayList
, it removes all elements from the list, but it does not affect the arrays that were previously created. The arrays (array1
andarray2
) are separate objects created during the conversion, and their contents remain unchanged after clearing the list.
6.2. From Array to List
6.2.1. asList()
When converting an array to an ArrayList
, you can use Arrays.asList()
to create a fixed-size List
backed by the original array. When a change is made to one, it is available in the other. Here’s an example using a String
array:
import java.util.Arrays;
import java.util.List;
public class ArrayToListExample {
public static void main(String[] args) {
String[] stringArray = {"apple", "banana", "cherry"};
List<String> stringList = Arrays.asList(stringArray);
System.out.println("List size: " + stringList.size()); // List size: 3
// Set an element in the list (backed by the original array)
stringList.set(1, "grapes");
System.out.println(stringArray[1]); // grapes
System.out.println(stringList); // [apple, grapes, cherry]
// Modify the original array
stringArray[0] = "mango";
System.out.println(stringArray[0]); // mango
System.out.println(stringList); // [mango, grapes, cherry]
// Attempt to remove an element from the list
stringList.remove(0); // UnsupportedOperationException
}
}
- List Initialization:
- We initialize a
String
array (stringArray
) with three elements. - We use
Arrays.asList(stringArray)
to create aList<String>
(stringList
). The list is backed by the original array.
- We initialize a
- Setting Element in the List:
- We set the element at index 1 in the list to “grapes” using
stringList.set(1, "grapes")
. - This modification is reflected in both the array and the list.
- We set the element at index 1 in the list to “grapes” using
- Modifying the Original Array:
- We modify the original array by changing the element at index 0 to “mango” (
stringArray[0] = "mango"
). - The modification is also reflected in the list.
- We modify the original array by changing the element at index 0 to “mango” (
- Attempting to Remove:
- We attempt to remove an element from the list using
stringList.remove(0)
, which results inUnsupportedOperationException
. This is expected since the list is fixed-size (backed by the original array).
- We attempt to remove an element from the list using
The key takeaway is that modifications made to the array or the list are reflected in both, as they share the same underlying data. However, operations that change the size of the list (e.g., adding or removing elements) will result in an UnsupportedOperationException
.
6.2.2. List.of()
Another option is to create an immutable List. That means you cannot change the values or the size of the List
public class ImmutableArrayListExample {
public static void main(String[] args) {
// Create a String array
String[] array = {"apple", "orange"};
// Create an immutable List from the array
List<String> immutableList = List.of(array);
// Change the original array
array[0] = "banana";
// Print the immutable list and the array
System.out.println("Immutable List: " + immutableList);
System.out.println("Modified Array: " + Arrays.toString(array));
// Attempt to modify the immutable list
try {
immutableList.set(1, "test");
} catch (UnsupportedOperationException e) {
System.out.println("UnsupportedOperationException: " + e.getMessage());
}
}
}
output:
Immutable List: [apple, orange]
Modified Array: [banana, orange]
UnsupportedOperationException: null
- List Initialization:
- We create a
String
array (array
) with two elements: “apple” and “orange”. - We create an immutable
List<String>
(immutableList
) usingList.of(array)
.
- We create a
- Changing the Original Array:
- We modify the original array by changing the element at index 0 to “banana” (
array[0] = "banana"
).
- We modify the original array by changing the element at index 0 to “banana” (
- Printing Results:
- We print the contents of the immutable list and the modified array.
- The printed output shows that changes made to the array are not reflected in the immutable list.
- Attempting to Modify the Immutable List:
- We attempt to modify the immutable list using
immutableList.set(1, "test")
, resulting inUnsupportedOperationException
. - This is expected since the list is immutable, and attempting to modify it will throw an exception.
- We attempt to modify the immutable list using
Creating an immutable list is useful when you want to ensure that the contents of the list remain constant and cannot be modified after creation. The List.of()
method provides a convenient way to create such an immutable list from an array or other iterable sources.
6.3.3. Using Varargs to Create a List
Both List.of() and Arrays.asList() take varargs, which let you pass in an array or just type out the String values. This is handy to easily create and populate a List on one line.
// Create a List using Arrays.asList with varargs
List<String> listFromArray = Arrays.asList("apple", "orange", "banana");
// Create a List using List.of with varargs
List<String> listOfFruits = List.of("apple", "orange", "banana");