Skip to lesson
CodeLangs AISoftware Training Institute
Arrays

Chapter 8 · Java Data Structures

Arrays

Master Java arrays from declaration and creation through indexing, traversal, one-dimensional, multidimensional and jagged arrays, arrays with methods and objects, copying, sorting, searching, comparing, filling with java.util.Arrays, and the common array exceptions and mistakes developers run into in production.

  • 3,942words
  • 18min read
  • 20quiz items
  • 18practice tools

We are going to learn Java Arrays from absolute beginner level through practical coding, internal behavior, common mistakes, production usage, revision, and interview preparation. This chapter includes declaration, creation, initialization, indexing, one-dimensional and multidimensional arrays, jagged arrays, traversal, arrays with methods and objects, copying, sorting, searching, comparing, filling, java.util.Arrays, and common array exceptions.


Imagine that you are building a small application.

You need to store the marks of one student.

That is easy:

Java
int mark = 80;

Now suppose you need to store marks for five students.

You could write:

Java
int mark1 = 80;
int mark2 = 75;
int mark3 = 90;
int mark4 = 65;
int mark5 = 88;

For five values, this may still look manageable.

But now imagine:

  • 100 students
  • 1,000 employees
  • 10,000 product prices
  • thousands of sensor readings

Would you create thousands of separate variables?

Obviously, that would become difficult to write, process, search, sort, and maintain.

What we need is one variable capable of representing multiple values of the same type.

That brings us to one of Java's fundamental data structures.

1. What Is an Array?#

An array is an object that stores a fixed number of values of the same type.

For example:

Java
int[] marks = {80, 75, 90, 65, 88};

Here:

  • marks is an array variable.
  • It represents five int values.
  • All elements are of type int.
  • Each value has a numeric position called an index.

Think of the array like numbered storage boxes:

Output
Array: marks

Index       0      1      2      3      4
          ┌────┬────┬────┬────┬────┐
Value     │ 80 │ 75 │ 90 │ 65 │ 88 │
          └────┴────┴────┴────┴────┘

Notice something important:

The first position is 0, not 1.

We will shortly understand why indexing matters.

Simple definition#

A Java array is a fixed-size object containing multiple elements of one declared type, where each element is accessed using an integer index.

2. Why Are Arrays Used?#

Before arrays, suppose we had:

Java
int mark1 = 80;
int mark2 = 75;
int mark3 = 90;
int mark4 = 65;
int mark5 = 88;

How would you calculate their total?

Java
int total = mark1 + mark2 + mark3 + mark4 + mark5;

Now imagine 1,000 marks.

This design does not scale.

With an array:

Java
int[] marks = {80, 75, 90, 65, 88};

int total = 0;

for (int mark : marks) {
    total += mark;
}

System.out.println(total);

Arrays provide several advantages:

  • Store many related values under one variable.
  • Access individual values using indexes.
  • Process elements using loops.
  • Pass a group of values to a method.
  • Return groups of values from methods.
  • Sort and search collections of values.
  • Represent matrices and tabular structures.
  • Build many higher-level data structures.

Arrays are also fundamental to Java because structures such as:

Java
String[] args

in the main() method are themselves arrays.


3. An Important Mental Model#

An array variable does not contain all elements directly in the ordinary local variable itself.

An array is an object.

Consider:

Java
int[] numbers = new int[3];

Conceptually:

Output
Local variable
numbers
   │
   │ reference
   ▼
Heap memory
┌───────────────┐
│ int[] object  │
├───────────────┤
│ 0 │ 0 │ 0     │
└───────────────┘

numbers contains a reference to the array object.

This becomes very important when we discuss:

  • assignment
  • passing arrays to methods
  • copying
  • comparison
  • mutation

4. Array Declaration#

Before using an array, we need to tell Java what type of array variable we want.

The preferred Java syntax is:

Java
int[] numbers;

This means:

numbers can refer to an array whose elements are int.

Another legal form is:

Java
int numbers[];

Both compile.

However, this is generally preferred:

Java
int[] numbers;

Why?

Because the type visually appears together:

Output
int[]

meaning:

array of int

For example:

Java
double[] prices;
String[] names;
char[] letters;
boolean[] flags;

At this point, only the reference variable has been declared.

No array object has necessarily been created yet.

For example:

Java
int[] numbers;

does not by itself create space for five integers.

That requires array creation.


5. Array Creation#

Now we need an actual array object.

Java uses the new keyword:

Java
int[] numbers = new int[5];

Let's break this down:

Output
int[]       numbers       =       new int[5];
  │            │                      │
type       variable              create array

new int[5] creates an array capable of storing exactly five int elements.

Conceptually:

Output
numbers
   │
   ▼
┌────┬────┬────┬────┬────┐
│  0 │  0 │  0 │  0 │  0 │
└────┴────┴────┴────┴────┘
   0    1    2    3    4

Notice that Java automatically initializes the elements.

We did not assign those zeros ourselves.

That leads us to an important rule.


6. Default Values in Arrays#

When Java creates an array, its elements receive default values.

Element TypeDefault Value
byte0
short0
int0
long0L
float0.0f
double0.0d
char'\u0000'
booleanfalse
Reference typesnull

Example:

Java
public class ArrayDefaults {
    public static void main(String[] args) {
        int[] numbers = new int[3];

        System.out.println(numbers[0]);
        System.out.println(numbers[1]);
        System.out.println(numbers[2]);
    }
}

Output:

Output
0
0
0

Now consider:

Java
String[] names = new String[3];

Its conceptual state is:

Output
Index       0       1       2
          ┌──────┬──────┬──────┐
Value     │ null │ null │ null │
          └──────┴──────┴──────┘

This is especially important because using an element before assigning an object may later cause a NullPointerException.


7. Array Initialization#

We have learned that:

Java
int[] numbers = new int[5];

creates an array using default values.

But frequently we already know the values.

Then we can initialize the array directly:

Java
int[] numbers = {10, 20, 30, 40, 50};

Java determines the size automatically.

Equivalent conceptual result:

Output
Index       0      1      2      3      4
          ┌────┬────┬────┬────┬────┐
Value     │ 10 │ 20 │ 30 │ 40 │ 50 │
          └────┴────┴────┴────┴────┘

Another form is:

Java
int[] numbers = new int[]{10, 20, 30, 40, 50};

Both are valid during declaration.

But notice this:

Java
int[] numbers;
numbers = {10, 20, 30};

This is invalid Java.

If initialization occurs separately, use:

Java
int[] numbers;
numbers = new int[]{10, 20, 30};

Why?#

The compact {...} initializer syntax is permitted as part of an array variable declaration.

For a later assignment, Java requires an explicit array creation expression.


8. Array Index#

Suppose:

Java
int[] numbers = {10, 20, 30, 40};

Java assigns indexes:

Output
Index       0      1      2      3
          ┌────┬────┬────┬────┐
Value     │ 10 │ 20 │ 30 │ 40 │
          └────┴────┴────┴────┘

The array contains four elements.

However, the valid indexes are:

Output
0
1
2
3

The rule is:

Output
First valid index = 0
Last valid index  = length - 1

For an array whose length is 4:

Output
last index = 4 - 1 = 3

This rule is extremely important.

Many beginner array bugs come from confusing:

Output
length

with:

Output
last index

They are not the same.


9. Accessing Array Elements#

To access an element, use:

Java
arrayName[index]

Example:

Java
public class AccessArray {
    public static void main(String[] args) {
        int[] numbers = {10, 20, 30, 40};

        System.out.println(numbers[0]);
        System.out.println(numbers[2]);
    }
}

Output:

Output
10
30

Let's visualize:

Output
numbers[0] → 10
numbers[1] → 20
numbers[2] → 30
numbers[3] → 40

10. Updating Array Elements#

Array elements are mutable.

That means we can replace an existing element.

Example:

Java
int[] numbers = {10, 20, 30};

numbers[1] = 500;

Before:

Output
[10, 20, 30]

After:

Output
[10, 500, 30]

Complete example:

Java
public class UpdateArray {
    public static void main(String[] args) {
        int[] numbers = {10, 20, 30};

        numbers[1] = 500;

        System.out.println(numbers[1]);
    }
}

Output:

Output
500

One important distinction:

The contents can change.

The length cannot change after array creation.


11. Fixed Size — A Fundamental Property#

Consider:

Java
int[] numbers = new int[5];

The length is permanently 5 for that array object.

You cannot later say:

Java
numbers.length = 10;

That does not compile.

You can make numbers refer to a different array:

Java
numbers = new int[10];

But that creates another array object.

It does not resize the original array.

Conceptually:

Output
Before

numbers ──► int[5]


After

numbers ──► int[10]

The original int[5] becomes eligible for garbage collection if nothing else references it.

This fixed-size characteristic is one major difference between Java arrays and dynamic collections such as ArrayList.


12. Array Length#

Every Java array has a field called:

Java
length

Example:

Java
int[] numbers = {10, 20, 30, 40};

System.out.println(numbers.length);

Output:

Output
4

Notice:

Java
numbers.length

not:

Java
numbers.length()

Why?

Because length is a field of an array, not a method call.

This is commonly confused with:

Java
String.length()

and:

Java
ArrayList.size()

Comparison:

StructureSize operation
Arrayarray.length
Stringstring.length()
ArrayListlist.size()

This is a very common interview and beginner question.


13. One-Dimensional Arrays#

Until now, our arrays have been one-dimensional.

Example:

Java
int[] scores = {90, 80, 70, 60};

Conceptually:

Output
[90] [80] [70] [60]

You can think of this as one sequence of elements.

A complete example:

Java
public class OneDimensionalArray {
    public static void main(String[] args) {
        String[] cities = {"Pune", "Mumbai", "Delhi"};

        System.out.println(cities[0]);
        System.out.println(cities[1]);
        System.out.println(cities[2]);
    }
}

Output:

Output
Pune
Mumbai
Delhi

14. Array Traversal#

Suppose an array contains 1,000 elements.

Would you write:

Java
System.out.println(numbers[0]);
System.out.println(numbers[1]);
System.out.println(numbers[2]);

one thousand times?

No.

We use loops.

Processing elements sequentially is called array traversal.


15. Traversing with a Traditional for Loop#

Example:

Java
public class ArrayTraversal {
    public static void main(String[] args) {
        int[] numbers = {10, 20, 30, 40};

        for (int i = 0; i < numbers.length; i++) {
            System.out.println(numbers[i]);
        }
    }
}

Output:

Output
10
20
30
40

Let's understand the loop:

Java
for (int i = 0; i < numbers.length; i++)

We start:

Output
i = 0

because the first index is 0.

We continue while:

Java
i < numbers.length

For a length of 4:

Output
i = 0, 1, 2, 3

When i becomes 4:

Output
4 < 4

is false.

Therefore the loop ends safely.


16. A Classic Off-by-One Error#

Look carefully:

Java
for (int i = 0; i <= numbers.length; i++) {
    System.out.println(numbers[i]);
}

What is wrong?

Suppose:

Java
numbers.length == 4

Because of:

Java
i <= numbers.length

the loop eventually allows:

Java
i == 4

Then Java tries:

Java
numbers[4]

But valid indexes are only:

Output
0, 1, 2, 3

The result is:

Output
ArrayIndexOutOfBoundsException

Correct:

Java
for (int i = 0; i < numbers.length; i++) {
    System.out.println(numbers[i]);
}

Memory rule#

Output
Array traversal by index:
0 <= index < array.length

17. Enhanced for Loop with Arrays#

Sometimes we don't care about indexes.

We simply want every value.

Instead of:

Java
for (int i = 0; i < numbers.length; i++) {
    System.out.println(numbers[i]);
}

we can write:

Java
for (int number : numbers) {
    System.out.println(number);
}

This syntax is called:

  • enhanced for loop
  • for-each loop

Read it naturally as:

For each number in numbers.

Example:

Java
public class EnhancedForExample {
    public static void main(String[] args) {
        int[] numbers = {10, 20, 30};

        for (int number : numbers) {
            System.out.println(number);
        }
    }
}

Output:

Output
10
20
30

18. Traditional for vs Enhanced for#

These loops are related but serve different needs.

RequirementTraditional forEnhanced for
Read every elementYesYes
Need indexYesNo direct index
Modify array by indexExcellentNot directly
Traverse backwardsYesNo
Skip indexes easilyYesLess suitable
Simple sequential readingMore verboseExcellent

Decision rule:

Output
Need the index?
→ traditional for

Need custom traversal direction?
→ traditional for

Need to replace array elements?
→ traditional for

Only need to read each value?
→ enhanced for

19. A Very Important Enhanced for Trap#

Consider:

Java
int[] numbers = {10, 20, 30};

for (int number : numbers) {
    number = 100;
}

Will the array become:

Output
[100, 100, 100]

No.

Why?

number receives the element's value.

Changing the local loop variable does not replace the corresponding array slot.

After the loop:

Output
[10, 20, 30]

To replace elements:

Java
for (int i = 0; i < numbers.length; i++) {
    numbers[i] = 100;
}

Now:

Output
[100, 100, 100]

20. Two-Dimensional Arrays#

So far our arrays look like a single row:

Output
[10] [20] [30]

But suppose we need to represent student marks across subjects:

Output
              Java   SQL   Angular
Student 1      80     90      75
Student 2      70     85      88

One-dimensional representation becomes less natural.

We need rows and columns.

That leads to a two-dimensional array.

Java
int[][] marks = {
    {80, 90, 75},
    {70, 85, 88}
};

Conceptually:

Output
              Column
             0    1    2
           ┌────┬────┬────┐
Row 0      │ 80 │ 90 │ 75 │
           ├────┼────┼────┤
Row 1      │ 70 │ 85 │ 88 │
           └────┴────┴────┘

Access:

Java
marks[0][0]

returns:

Output
80

And:

Java
marks[1][2]

returns:

Output
88

21. Java's Two-Dimensional Arrays Are Really Arrays of Arrays#

This is important.

Java does not require every row to be part of one flat rectangular object.

Consider:

Java
int[][] matrix = new int[3][4];

Conceptually:

Output
matrix
  │
  ▼
┌────────┬────────┬────────┐
│ ref    │ ref    │ ref    │
└───┬────┴───┬────┴───┬────┘
    │        │        │
    ▼        ▼        ▼
 [0,0,0,0] [0,0,0,0] [0,0,0,0]

The outer array stores references to inner arrays.

This explains why Java supports jagged arrays.


22. Creating a 2D Array#

You can create:

Java
int[][] matrix = new int[2][3];

This gives:

Output
2 rows
3 elements per row

Access:

Java
matrix[0][0] = 10;
matrix[0][1] = 20;
matrix[0][2] = 30;

matrix[1][0] = 40;
matrix[1][1] = 50;
matrix[1][2] = 60;

23. Traversing a 2D Array#

We need one loop for rows and another for the elements inside each row.

Java
public class TwoDimensionalTraversal {
    public static void main(String[] args) {
        int[][] matrix = {
            {10, 20, 30},
            {40, 50, 60}
        };

        for (int row = 0; row < matrix.length; row++) {
            for (int column = 0; column < matrix[row].length; column++) {
                System.out.print(matrix[row][column] + " ");
            }

            System.out.println();
        }
    }
}

Output:

Output
10 20 30
40 50 60

Notice:

Java
matrix.length

means:

number of rows

while:

Java
matrix[row].length

means:

number of elements in that specific row

Using matrix[row].length becomes especially important for jagged arrays.


24. Enhanced for with 2D Arrays#

We can also write:

Java
int[][] matrix = {
    {10, 20, 30},
    {40, 50, 60}
};

for (int[] row : matrix) {
    for (int value : row) {
        System.out.print(value + " ");
    }

    System.out.println();
}

Here:

Java
int[] row

makes sense because each element of:

Java
int[][]

is itself an:

Java
int[]

That is a useful way to understand multidimensional Java arrays.


25. Multidimensional Arrays#

Java supports arrays with more dimensions.

For example:

Java
int[][][] data = new int[2][3][4];

You can think of it as:

Output
array
  ↓
arrays
  ↓
arrays
  ↓
int values

Access:

Java
data[0][1][2]

However, use higher-dimensional arrays only when the domain genuinely requires them.

Three-dimensional arrays can be useful for things like:

  • coordinates
  • image data
  • simulation grids
  • structured numeric datasets

But overly complex multidimensional arrays can become difficult to maintain.


26. Jagged Arrays#

Now something interesting happens because Java's 2D arrays are arrays of arrays.

What if different rows need different lengths?

For example:

Output
Student 1 → 3 courses
Student 2 → 2 courses
Student 3 → 5 courses

A rectangular structure wastes space or does not model the requirement naturally.

Java allows:

Java
int[][] data = new int[3][];

data[0] = new int[3];
data[1] = new int[2];
data[2] = new int[5];

Conceptually:

Output
data
 │
 ├──► [0][0][0]
 │
 ├──► [0][0]
 │
 └──► [0][0][0][0][0]

This is called a jagged array.

Example with values:

Java
int[][] marks = {
    {80, 90, 70},
    {75, 85},
    {60, 70, 80, 90}
};

This is legal Java.


27. Traversing a Jagged Array Correctly#

This is correct:

Java
for (int row = 0; row < marks.length; row++) {
    for (int column = 0; column < marks[row].length; column++) {
        System.out.println(marks[row][column]);
    }
}

Do not assume:

Java
marks[0].length

is the length of every row.

Each row may differ.


28. Passing Arrays to Methods#

Suppose we frequently calculate totals.

Instead of repeating the logic:

Java
int total = 0;

for (int number : numbers) {
    total += number;
}

we can place it inside a method.

Java
public class ArrayMethodExample {
    public static void main(String[] args) {
        int[] numbers = {10, 20, 30};

        printArray(numbers);
    }

    static void printArray(int[] values) {
        for (int value : values) {
            System.out.println(value);
        }
    }
}

The parameter:

Java
int[] values

means:

This method expects a reference to an int[].

29. Does Java Copy the Whole Array When Passing It?#

This is an important interview concept.

Consider:

Java
int[] numbers = {10, 20, 30};

change(numbers);

Java is always pass-by-value.

But what value is being passed here?

The value stored in numbers is an array reference.

A copy of that reference value is passed.

So both references point to the same array object.

Example:

Java
public class ArrayMutation {
    public static void main(String[] args) {
        int[] numbers = {10, 20, 30};

        change(numbers);

        System.out.println(numbers[0]);
    }

    static void change(int[] values) {
        values[0] = 999;
    }
}

Output:

Output
999

Conceptually:

Output
main:

numbers ────────────┐
                    │
                    ▼
              [10, 20, 30]
                    ▲
                    │
method:
values ─────────────┘

Then:

Java
values[0] = 999;

changes the shared array object.


30. But Reassigning the Parameter Is Different#

Consider:

Java
public class ArrayReassignment {
    public static void main(String[] args) {
        int[] numbers = {10, 20, 30};

        replace(numbers);

        System.out.println(numbers[0]);
    }

    static void replace(int[] values) {
        values = new int[]{100, 200, 300};
    }
}

Output:

Output
10

Why?

The method received a copy of the original reference.

Then:

Java
values = new int[]{100, 200, 300};

changes only the method's local reference.

Conceptually:

Output
Before reassignment

numbers ────┐
            ▼
         [10,20,30]
            ▲
values ─────┘


After reassignment

numbers ─────► [10,20,30]

values ──────► [100,200,300]

Important interview rule#

Java is always pass-by-value. For arrays, the passed value is a copy of the array reference.

31. Returning Arrays from Methods#

A method can also create and return an array.

Example:

Java
public class ReturnArrayExample {
    public static void main(String[] args) {
        int[] result = createNumbers();

        for (int value : result) {
            System.out.println(value);
        }
    }

    static int[] createNumbers() {
        return new int[]{10, 20, 30};
    }
}

The method return type is:

Java
int[]

because the method returns an array of integers.


32. Array of Objects#

Until now we mostly stored primitive values:

Java
int[]
double[]
char[]

But an array can also store references to objects.

Consider:

Java
String[] names = new String[3];

String is a reference type.

Initially:

Output
[null, null, null]

Then:

Java
names[0] = "Amit";
names[1] = "Neha";
names[2] = "Rahul";

Now:

Output
names
  │
  ├──► "Amit"
  ├──► "Neha"
  └──► "Rahul"

33. Custom Objects in Arrays#

Suppose:

Java
class Employee {
    String name;

    Employee(String name) {
        this.name = name;
    }
}

Now:

Java
Employee[] employees = new Employee[3];

A beginner often assumes this creates three Employee objects.

It does not.

It creates an array capable of holding three Employee references.

Initially:

Output
[null, null, null]

We still need:

Java
employees[0] = new Employee("Amit");
employees[1] = new Employee("Neha");
employees[2] = new Employee("Rahul");

Complete example:

Java
public class ObjectArrayExample {
    public static void main(String[] args) {
        Employee[] employees = new Employee[3];

        employees[0] = new Employee("Amit");
        employees[1] = new Employee("Neha");
        employees[2] = new Employee("Rahul");

        for (Employee employee : employees) {
            System.out.println(employee.name);
        }
    }
}

class Employee {
    String name;

    Employee(String name) {
        this.name = name;
    }
}

Output:

Output
Amit
Neha
Rahul

34. A Common Object Array Mistake#

This code:

Java
Employee[] employees = new Employee[3];

System.out.println(employees[0].name);

causes a runtime problem.

Why?

Because:

Java
employees[0]

is currently:

Output
null

Then Java effectively tries to access:

Java
null.name

which produces:

Output
NullPointerException

Correct approach:

Java
employees[0] = new Employee("Amit");

System.out.println(employees[0].name);

35. Array Assignment Does Not Copy Elements#

Now we reach one of the most misunderstood topics.

Consider:

Java
int[] first = {10, 20, 30};

int[] second = first;

Did Java create another array?

No.

Both variables refer to the same array.

Output
first ──────┐
            ▼
        [10,20,30]
            ▲
second ─────┘

So:

Java
second[0] = 999;

also affects what is seen through first.

Example:

Java
public class ArrayReferenceAssignment {
    public static void main(String[] args) {
        int[] first = {10, 20, 30};

        int[] second = first;

        second[0] = 999;

        System.out.println(first[0]);
    }
}

Output:

Output
999

This is reference assignment, not array copying.


36. Copying Arrays#

Sometimes we genuinely want a second array.

Java offers several approaches:

  • manual loop
  • clone()
  • System.arraycopy()
  • Arrays.copyOf()
  • Arrays.copyOfRange()

Each has useful scenarios.


37. Copying with a Loop#

The most educational approach is:

Java
int[] source = {10, 20, 30};
int[] copy = new int[source.length];

for (int i = 0; i < source.length; i++) {
    copy[i] = source[i];
}

Now there are two independent primitive arrays:

Output
source ───► [10,20,30]

copy ─────► [10,20,30]

If:

Java
copy[0] = 999;

the source remains unchanged.


38. clone()#

Arrays support cloning:

Java
int[] source = {10, 20, 30};

int[] copy = source.clone();

For a one-dimensional primitive array, this copies the primitive values.

Example:

Java
copy[0] = 999;

System.out.println(source[0]);

Output:

Output
10

However, when an array contains object references, cloning the array does not clone the referenced objects.

That distinction is called shallow copying.

We will revisit it shortly.


39. System.arraycopy()#

Java provides:

Java
System.arraycopy(
    source,
    sourcePosition,
    destination,
    destinationPosition,
    length
);

Example:

Java
public class ArrayCopyExample {
    public static void main(String[] args) {
        int[] source = {10, 20, 30, 40, 50};
        int[] destination = new int[5];

        System.arraycopy(source, 0, destination, 0, source.length);

        for (int value : destination) {
            System.out.println(value);
        }
    }
}

Output:

Output
10
20
30
40
50

The call:

Java
System.arraycopy(source, 0, destination, 0, source.length);

means:

Output
source array       → source
start from         → index 0
destination array  → destination
write from         → index 0
number of elements → source.length

40. Partial Copy with System.arraycopy()#

Suppose:

Java
int[] source = {10, 20, 30, 40, 50};
int[] destination = new int[3];

We want:

Output
[20, 30, 40]

Use:

Java
System.arraycopy(source, 1, destination, 0, 3);

Meaning:

Output
source index 1 → 20
copy 3 elements
destination starts at index 0

Result:

Output
[20, 30, 40]

41. Arrays.copyOf()#

Before using this method, a new class appears:

Java
java.util.Arrays

The Arrays class contains static utility methods designed for arrays.

Import it:

Java
import java.util.Arrays;

Then:

Java
int[] source = {10, 20, 30};

int[] copy = Arrays.copyOf(source, source.length);

You can also request a different length:

Java
int[] copy = Arrays.copyOf(source, 5);

If the source is:

Output
[10, 20, 30]

the new result becomes:

Output
[10, 20, 30, 0, 0]

because extra primitive elements receive default values.


42. Arrays.copyOfRange()#

Suppose:

Java
int[] numbers = {10, 20, 30, 40, 50};

We want:

Output
[20, 30, 40]

Use:

Java
int[] result = Arrays.copyOfRange(numbers, 1, 4);

The range follows:

Output
from index → inclusive
to index   → exclusive

So:

Output
1 included
4 excluded

Elements copied:

Output
index 1 → 20
index 2 → 30
index 3 → 40

Result:

Output
[20, 30, 40]

This inclusive/exclusive rule is an important interview detail.


43. Shallow Copy with Object Arrays#

Suppose:

Java
Employee[] original = {
    new Employee("Amit"),
    new Employee("Neha")
};

Employee[] copy = original.clone();

There are two different array objects.

But their elements point to the same Employee objects.

Conceptually:

Output
original ──► [ref A][ref B]
               │      │
               │      └────► Employee("Neha")
               └───────────► Employee("Amit")

copy ─────► [ref A][ref B]

Therefore:

Java
copy[0].name = "Changed";

also changes what:

Java
original[0].name

shows.

This is called a shallow copy.

A deep copy would require creating independent copies of the referenced mutable objects.


44. Sorting Arrays#

Suppose:

Java
int[] numbers = {40, 10, 30, 20};

You could manually implement a sorting algorithm.

But for ordinary Java application code, Java provides:

Java
Arrays.sort(numbers);

Example:

Java
import java.util.Arrays;

public class SortArrayExample {
    public static void main(String[] args) {
        int[] numbers = {40, 10, 30, 20};

        Arrays.sort(numbers);

        System.out.println(Arrays.toString(numbers));
    }
}

Output:

Output
[10, 20, 30, 40]

Notice:

Java
Arrays.sort(numbers);

modifies the existing array.

It does not normally return a new sorted array.


45. Sorting Object Arrays#

For types such as String:

Java
String[] names = {"Rahul", "Amit", "Neha"};

Arrays.sort(names);

Result:

Output
[Amit, Neha, Rahul]

For custom objects, ordering must be defined using mechanisms such as:

  • Comparable
  • Comparator

Those are larger concepts belonging primarily to object ordering and collections, so we will not turn this arrays chapter into a complete comparator course.

But you should understand this boundary:

Java can directly sort primitive arrays and naturally comparable object arrays. Custom ordering requires an ordering rule.

46. Searching Arrays#

Suppose an array contains:

Output
[10, 20, 30, 40, 50]

We want to find 30.

The simplest approach is a linear search:

Java
public class LinearSearchExample {
    public static void main(String[] args) {
        int[] numbers = {10, 20, 30, 40, 50};
        int target = 30;

        int foundIndex = -1;

        for (int i = 0; i < numbers.length; i++) {
            if (numbers[i] == target) {
                foundIndex = i;
                break;
            }
        }

        System.out.println(foundIndex);
    }
}

Output:

Output
2

We used:

Java
-1

to mean:

Not found yet.

For sorted data, Java provides:

Java
Arrays.binarySearch()

Example:

Java
import java.util.Arrays;

public class BinarySearchExample {
    public static void main(String[] args) {
        int[] numbers = {10, 20, 30, 40, 50};

        int index = Arrays.binarySearch(numbers, 30);

        System.out.println(index);
    }
}

Output:

Output
2

But there is an important prerequisite:

Use Arrays.binarySearch() meaningfully on data sorted according to the expected ordering.

Do not assume that calling it on an unsorted array provides a meaningful search result.


48. When binarySearch() Does Not Find the Value#

This is a common interview trap.

Suppose:

Java
int[] numbers = {10, 20, 30, 40};

System.out.println(Arrays.binarySearch(numbers, 25));

The return is not simply -1 in every missing case.

The method returns:

Output
-(insertion point) - 1

The insertion point for 25 would be index 2.

Therefore:

Output
-(2) - 1 = -3

So output:

Output
-3

Why encode the insertion position?

Because the caller can determine where the absent element would belong while preserving sorted order.


49. Comparing Arrays#

Now suppose:

Java
int[] first = {10, 20, 30};
int[] second = {10, 20, 30};

A beginner may write:

Java
System.out.println(first == second);

What does == compare here?

The references.

These are two different arrays.

Therefore:

Output
false

To compare contents:

Java
Arrays.equals(first, second)

returns:

Output
true

Example:

Java
import java.util.Arrays;

public class CompareArrays {
    public static void main(String[] args) {
        int[] first = {10, 20, 30};
        int[] second = {10, 20, 30};

        System.out.println(first == second);
        System.out.println(Arrays.equals(first, second));
    }
}

Output:

Output
false
true

50. == vs Arrays.equals()#

Question==Arrays.equals()
Same array reference?YesNot its main purpose
Same element contents?NoYes
Useful for primitive array content comparison?NoYes

Memory rule:

Output
Same object?
→ ==

Same one-dimensional array contents?
→ Arrays.equals()

51. Comparing Nested Arrays#

Consider:

Java
int[][] first = {
    {1, 2},
    {3, 4}
};

int[][] second = {
    {1, 2},
    {3, 4}
};

For nested array content comparison, use:

Java
Arrays.deepEquals(first, second);

This performs nested content comparison.

Similarly, nested arrays can be rendered with:

Java
Arrays.deepToString(array);

52. Printing Arrays Correctly#

Consider:

Java
int[] numbers = {10, 20, 30};

System.out.println(numbers);

You should not expect:

Output
[10, 20, 30]

Arrays do not override object string rendering in a way that directly prints their contents.

For one-dimensional arrays:

Java
System.out.println(Arrays.toString(numbers));

Output:

Output
[10, 20, 30]

For multidimensional arrays:

Java
System.out.println(Arrays.deepToString(matrix));

53. Filling Arrays#

Suppose you need an array containing:

Output
[-1, -1, -1, -1, -1]

You could write a loop.

But Java provides:

Java
Arrays.fill()

Example:

Java
import java.util.Arrays;

public class FillArrayExample {
    public static void main(String[] args) {
        int[] numbers = new int[5];

        Arrays.fill(numbers, -1);

        System.out.println(Arrays.toString(numbers));
    }
}

Output:

Output
[-1, -1, -1, -1, -1]

This is useful for:

  • sentinel values
  • initialization
  • resetting buffers
  • preparing algorithmic state

54. Important java.util.Arrays Methods#

At this point, you can see why the Arrays utility class exists.

Frequently used methods include:

MethodPurpose
Arrays.toString()readable 1D representation
Arrays.deepToString()readable nested-array representation
Arrays.sort()sort elements
Arrays.binarySearch()binary search
Arrays.equals()compare 1D contents
Arrays.deepEquals()compare nested contents
Arrays.fill()fill elements
Arrays.copyOf()copy with requested length
Arrays.copyOfRange()copy a range

55. Common Array Exceptions#

Arrays are simple but unforgiving around invalid indexes and null references.

Two major runtime problems are:

  • ArrayIndexOutOfBoundsException
  • NullPointerException

Other problems can occur while copying or storing incompatible reference types.

Let's understand the most important ones.


56. ArrayIndexOutOfBoundsException#

Example:

Java
int[] numbers = {10, 20, 30};

System.out.println(numbers[3]);

Array length:

Output
3

Valid indexes:

Output
0, 1, 2

Index 3 is invalid.

The program throws:

Output
ArrayIndexOutOfBoundsException

The same happens with negative indexes:

Java
numbers[-1]

Valid index rule#

Output
0 <= index < array.length

57. NullPointerException with Arrays#

Consider:

Java
int[] numbers = null;

System.out.println(numbers.length);

numbers does not refer to an array object.

Therefore accessing:

Java
numbers.length

causes:

Output
NullPointerException

Similarly:

Java
String[] names = new String[3];

System.out.println(names[0].length());

names itself exists.

But:

Java
names[0]

is null.

Calling:

Java
length()

on that null reference causes NullPointerException.

These are two different null situations:

Output
Array reference null
vs
Element inside array null

58. ArrayStoreException#

A slightly more advanced array trap appears because Java arrays are covariant.

First, what does covariance mean here?

Java allows:

Java
Object[] values = new String[3];

because String is a subtype of Object.

This compiles.

Now consider:

Java
values[0] = "Hello";

Valid.

But:

Java
values[1] = Integer.valueOf(10);

The variable type is:

Java
Object[]

so this might look legal at compile time.

However, the actual array object is:

Java
String[]

A String[] cannot contain an Integer.

Therefore Java throws:

Output
ArrayStoreException

Example:

Java
public class ArrayStoreExample {
    public static void main(String[] args) {
        Object[] values = new String[2];

        values[0] = "Java";
        values[1] = Integer.valueOf(10);
    }
}

This is an important contrast between arrays and generic collections.


59. Negative Array Size#

This is invalid at runtime:

Java
int[] numbers = new int[-5];

It compiles because -5 is a valid integer expression.

But Java cannot construct an array with negative length.

Runtime result:

Output
NegativeArraySizeException

60. Zero-Length Arrays#

This is perfectly valid:

Java
int[] numbers = new int[0];

Then:

Java
numbers.length

is:

Output
0

There are simply no valid element indexes.

An empty array can be useful when a method wants to return:

no results

without returning null.

For many APIs, returning an empty array can make calling code simpler.


61. Arrays and Memory#

Suppose:

Java
int[] numbers = new int[1_000_000];

An array has contiguous logical indexed storage for its elements, and allocating a very large array requires sufficient heap memory.

The practical considerations include:

  • array length
  • element type
  • object references
  • nested arrays
  • temporary copies
  • sorting/copying operations

For primitive arrays, the array stores primitive values.

For object arrays, the array stores references, not the objects themselves.

Example:

Java
Employee[] employees = new Employee[1000];

This creates storage for 1,000 Employee references.

It does not automatically create 1,000 Employee objects.


62. Arrays Are Mutable#

Consider:

Java
int[] numbers = {10, 20, 30};

numbers[0] = 999;

The array content changes.

This mutability matters when:

  • sharing arrays across methods
  • exposing internal state
  • working with multiple references
  • processing data concurrently

If two parts of a program share the same mutable array, changes made by one can be visible to the other.


63. Defensive Copying#

Suppose a class accepts an array and stores the reference directly:

Java
class Report {
    private final int[] scores;

    Report(int[] scores) {
        this.scores = scores;
    }
}

Now external code still has that same array reference.

It can modify the array after constructing Report.

A safer approach when isolation is required is:

Java
class Report {
    private final int[] scores;

    Report(int[] scores) {
        this.scores = scores.clone();
    }
}

And if returning it:

Java
public int[] getScores() {
    return scores.clone();
}

This is called defensive copying.

Important nuance:

For arrays of mutable objects, a shallow array clone may still share referenced objects.


64. Thread Safety#

Arrays themselves do not automatically make compound operations thread-safe.

Suppose several threads modify:

Java
int[] counters

simultaneously.

The array provides indexed storage, but coordination between threads remains your responsibility.

Whether synchronization is needed depends on:

  • operations being performed
  • whether multiple threads mutate the same elements
  • visibility requirements
  • higher-level concurrency design

Do not assume:

It's an array, therefore access is thread-safe.

That conclusion is incorrect.


65. Array vs ArrayList#

Arrays often get compared with ArrayList.

Let's understand the decision, rather than memorizing definitions.

DimensionArrayArrayList
SizeFixedDynamically resizable
Primitive elementsDirectly supportedUses wrapper types for generics
Indexed accessYesYes
SyntaxLanguage featureCollection class
Length/size.length.size()
Add/remove operationsManualBuilt-in methods
Generic API integrationLimitedStrong
Low-level fixed structureExcellentLess direct
Dynamic application dataLess convenientOften preferred

Decision rule:

Output
Fixed number of values?
Performance-sensitive primitive storage?
Low-level structured data?
→ Array may be appropriate

Dynamic number of application objects?
Frequent add/remove?
Need Collections APIs?
→ ArrayList is often more convenient

Arrays are not obsolete.

They remain fundamental and useful.


66. Array vs Individual Variables#

Use individual variables when values represent different concepts:

Java
int age;
double salary;
String name;

Do not create an array merely because multiple variables exist.

Use an array when values belong to the same conceptual sequence or group:

Java
int[] monthlySales;
double[] temperatures;
String[] employeeNames;

67. Correct vs Risky Array Design#

Risky#

Java
int[] data = new int[10000];

when only ten values may ever be needed and there is no clear reason to preallocate 10,000.

Why?

It may waste memory and communicate the wrong design intent.

Better when size is genuinely fixed#

Java
int[] monthlySales = new int[12];

Why?

The domain has exactly 12 months.

The fixed size matches the business requirement.


68. Learning Example vs Production Approach#

Learning example#

Java
int[] marks = {80, 90, 75};

for (int mark : marks) {
    System.out.println(mark);
}

This is ideal for understanding arrays.

Typical production consideration#

In a real system, ask:

  • Is the number of values fixed?
  • Will the data be loaded dynamically?
  • Is insertion/removal needed?
  • Is primitive storage beneficial?
  • Will external callers mutate the array?
  • Do we need defensive copies?
  • Is a collection API more maintainable?
  • Do we need concurrency controls?
  • Is a domain class more expressive?

Good production code starts with the requirement, not with loyalty to a particular data structure.


69. Common Mistakes#

Mistake 1 — Using <= array.length#

Mistake:

Java
for (int i = 0; i <= numbers.length; i++)

Why Developers Make It:

They think the last index equals the array length.

Why It Is Wrong:

Indexes run only to:

Output
length - 1

Possible Consequence:

ArrayIndexOutOfBoundsException.

Correct Approach:

Java
for (int i = 0; i < numbers.length; i++)

Debugging Signal:

Exception occurs near the end of traversal.

Interview Connection:

Classic off-by-one question.


Mistake 2 — Assuming Index Starts at 1#

Mistake:

Java
numbers[1]

when intending to access the first element.

Correct Rule:

First element:

Java
numbers[0]

Mistake 3 — Calling length()#

Wrong:

Java
numbers.length()

Correct:

Java
numbers.length

Arrays expose a length field.


Mistake 4 — Expecting System.out.println(array) to Print Contents#

Risky expectation:

Java
System.out.println(numbers);

Preferred:

Java
System.out.println(Arrays.toString(numbers));

For nested arrays:

Java
System.out.println(Arrays.deepToString(matrix));

Mistake 5 — Believing Assignment Copies an Array#

Wrong assumption:

Java
int[] second = first;

means independent copy.

It does not.

Both references point to the same array.

Use a copy operation when independence is required.


Mistake 6 — Forgetting Object Array Elements Start as null#

Java
Employee[] employees = new Employee[3];

does not create three employees.

Initialize each object before dereferencing it.


Mistake 7 — Using Binary Search on Unsorted Input#

Risky:

Java
int index = Arrays.binarySearch(numbers, target);

without ensuring sorting compatible with the search order.

Correct mental model:

Output
sort/order guarantee
        ↓
binary search

Mistake 8 — Misreading copyOfRange()#

Remember:

Output
from → inclusive
to   → exclusive

Mistake 9 — Modifying Enhanced-For Variable Instead of the Array Slot#

This does not replace primitive elements:

Java
for (int n : numbers) {
    n = 0;
}

Use indexed assignment:

Java
for (int i = 0; i < numbers.length; i++) {
    numbers[i] = 0;
}

Mistake 10 — Returning Internal Mutable Arrays Directly#

Potentially risky:

Java
public int[] getScores() {
    return scores;
}

Caller can modify your internal state.

When isolation is required:

Java
return scores.clone();

Mistake 11 — Assuming clone() Creates Deep Copies of Objects#

Java
Employee[] copy = original.clone();

creates another array but shares the referenced Employee objects.


Mistake 12 — Assuming Every 2D Row Has Same Length#

Risky:

Java
for (int j = 0; j < matrix[0].length; j++)

for jagged data.

Preferred:

Java
for (int j = 0; j < matrix[i].length; j++)

70. Important Edge Cases#

Empty array#

Java
int[] data = {};

Valid.

Length:

Output
0

Null array#

Java
int[] data = null;

No array object exists.


One-element array#

Java
int[] data = {10};

Valid index:

Output
0

Duplicate values#

Arrays allow duplicates:

Java
int[] values = {10, 10, 10};

No uniqueness rule exists.


Negative values#

Perfectly valid as element values:

Java
int[] values = {-10, -20};

Only negative array length is invalid.


Null elements#

Reference arrays may contain null:

Java
String[] names = {"Amit", null, "Neha"};

Handle elements appropriately before dereferencing.


71. Complete Decision Rules#

Output
Need multiple same-type fixed-count values?
→ Array

Need dynamic growth/shrink?
→ Consider ArrayList

Need every value only?
→ enhanced for

Need index/control/backward traversal?
→ traditional for

Need independent primitive array copy?
→ clone(), Arrays.copyOf(), System.arraycopy(), etc.

Need range copy?
→ Arrays.copyOfRange()

Need readable 1D printing?
→ Arrays.toString()

Need readable nested printing?
→ Arrays.deepToString()

Need 1D content comparison?
→ Arrays.equals()

Need nested content comparison?
→ Arrays.deepEquals()

Need sorting?
→ Arrays.sort()

Need binary searching?
→ sorted array + Arrays.binarySearch()

Need initialize all elements to same value?
→ Arrays.fill()

Need rows with different lengths?
→ jagged array

72. Practical Example — Student Marks#

Let's combine several concepts.

Requirement:

Store student marks, calculate total, average, highest mark, and sort a copy without modifying the original order.
Java
import java.util.Arrays;

public class StudentMarks {
    public static void main(String[] args) {
        int[] marks = {78, 92, 67, 88, 95};

        int total = calculateTotal(marks);
        double average = (double) total / marks.length;
        int highest = findHighest(marks);

        int[] sortedMarks = marks.clone();
        Arrays.sort(sortedMarks);

        System.out.println("Original: " + Arrays.toString(marks));
        System.out.println("Sorted: " + Arrays.toString(sortedMarks));
        System.out.println("Total: " + total);
        System.out.println("Average: " + average);
        System.out.println("Highest: " + highest);
    }

    static int calculateTotal(int[] marks) {
        int total = 0;

        for (int mark : marks) {
            total += mark;
        }

        return total;
    }

    static int findHighest(int[] marks) {
        int highest = marks[0];

        for (int mark : marks) {
            if (mark > highest) {
                highest = mark;
            }
        }

        return highest;
    }
}

Output:

Output
Original: [78, 92, 67, 88, 95]
Sorted: [67, 78, 88, 92, 95]
Total: 420
Average: 84.0
Highest: 95

Why clone before sorting?#

Because:

Java
Arrays.sort(marks);

would modify the original array.

We wanted both:

Output
original order
and
sorted order

Therefore:

Java
int[] sortedMarks = marks.clone();

creates a separate primitive array.


73. Internal Execution Map#

When Java executes:

Java
int[] numbers = new int[3];

think:

Output
Declare reference
      ↓
Evaluate new int[3]
      ↓
Allocate array object
      ↓
Initialize all elements to default int value 0
      ↓
Store reference in numbers
      ↓
numbers can access elements using indexes 0..2

When Java executes:

Java
int[] second = numbers;

think:

Output
Copy reference value
      ↓
Do NOT create new array
      ↓
Both variables reference same array

When Java executes:

Java
int[] copy = numbers.clone();

think:

Output
Create another array
      ↓
Copy array elements
      ↓
Primitive values independent
      ↓
Object references still shallow when elements are references

74. Complete Chapter Revision#

One-line definitions#

Array: Fixed-size object storing elements of one declared type.

Index: Numeric position used to access an array element.

Length: Number of slots in an array.

Traversal: Processing array elements sequentially.

Jagged array: Multidimensional array whose inner arrays may have different lengths.

Shallow copy: New outer array containing copied references to the same underlying objects.


Core syntax#

Declaration:

Java
int[] numbers;

Creation:

Java
numbers = new int[5];

Declaration + creation:

Java
int[] numbers = new int[5];

Initialization:

Java
int[] numbers = {10, 20, 30};

Access:

Java
numbers[0]

Update:

Java
numbers[1] = 50;

Length:

Java
numbers.length

Traversal#

Traditional:

Java
for (int i = 0; i < numbers.length; i++) {
    System.out.println(numbers[i]);
}

Enhanced:

Java
for (int number : numbers) {
    System.out.println(number);
}

2D syntax#

Java
int[][] matrix = {
    {1, 2},
    {3, 4}
};

Access:

Java
matrix[1][0]

Important API memory map#

Output
Print
→ Arrays.toString()

Print nested
→ Arrays.deepToString()

Sort
→ Arrays.sort()

Search sorted
→ Arrays.binarySearch()

Compare
→ Arrays.equals()

Compare nested
→ Arrays.deepEquals()

Fill
→ Arrays.fill()

Copy
→ Arrays.copyOf()

Copy range
→ Arrays.copyOfRange()

Low-level copy
→ System.arraycopy()

75. If You Remember Only 10 Things#

  1. Arrays store multiple elements of one declared type.
  2. Array size is fixed after creation.
  3. First index is 0.
  4. Last valid index is length - 1.
  5. Use array.length, not array.length().
  6. Array variables hold references to array objects.
  7. second = first does not copy the array.
  8. Object-array elements initially contain null.
  9. Arrays.equals() compares array contents; == compares references.
  10. Arrays.binarySearch() assumes appropriate sorted ordering.

76. Final Knowledge Map#

Output
Java Arrays
│
├── Foundation
│   ├── What is an array?
│   ├── Why arrays exist
│   ├── Fixed size
│   ├── Same declared element type
│   └── Array as an object/reference
│
├── Basic Operations
│   ├── Declaration
│   ├── Creation
│   ├── Initialization
│   ├── Default values
│   ├── Index
│   ├── Access
│   ├── Update
│   └── length
│
├── Structure
│   ├── One-dimensional
│   ├── Two-dimensional
│   ├── Multidimensional
│   └── Jagged
│
├── Traversal
│   ├── Traditional for
│   └── Enhanced for
│
├── Methods
│   ├── Passing arrays
│   ├── Pass-by-value reference semantics
│   └── Returning arrays
│
├── Reference Arrays
│   ├── String[]
│   ├── Custom objects
│   ├── null elements
│   └── ArrayStoreException
│
├── Copying
│   ├── Assignment is not copying
│   ├── Manual copy
│   ├── clone()
│   ├── System.arraycopy()
│   ├── Arrays.copyOf()
│   ├── Arrays.copyOfRange()
│   └── Shallow vs deeper object copying
│
├── java.util.Arrays
│   ├── sort()
│   ├── binarySearch()
│   ├── equals()
│   ├── deepEquals()
│   ├── fill()
│   ├── toString()
│   └── deepToString()
│
├── Exceptions
│   ├── ArrayIndexOutOfBoundsException
│   ├── NullPointerException
│   ├── ArrayStoreException
│   └── NegativeArraySizeException
│
├── Production
│   ├── Defensive copying
│   ├── Memory
│   ├── Mutability
│   ├── Thread safety
│   └── Array vs ArrayList
│
└── Interview
    ├── Index boundaries
    ├── References
    ├── Pass-by-value
    ├── Copy semantics
    ├── Object arrays
    ├── Arrays utility methods
    └── Edge cases

Practice lab

Prove what you just learned