Java

Java Tutorials – Arrays in Java

Hello people..! This is a new post in Java Tutorials – Arrays in Java. In this post I will talk about about using arrays in Java. Arrays in Java are different from arrays in C. Arrays in Java are actually objects. But understanding arrays as being-an-object point-of-view is not something beginners feel comfortable with. So this discussion will introduce new terms and concepts. So, let’s get started…!

Arrays in Java

Creating an array in Java has 3 steps –

  • Declaration – In this step, we specify the data type and the dimensions of the array that we are going to create. But remember, we don’t mention the sizes of dimensions yet. They are left empty.
  • Instantiation – In this step, we create the array, or allocate memory for the array, using the new keyword. It is in this step that we mention the sizes of the array dimensions.
  • Initialization – The array is always initialized to the data type’s default value. But we can make our own initializations.

Now, let’s look at the individual steps in a little more detail.

Declaration

This is how we declare a one-dimensional array in Java –

int[] array;

Well, you should have guesses it because we’ve been declaring arrays right from our first program…! Really..? Yeah..! In the main() method’s declaration..!

public static void main(String[] args) {
    // code
}

The formal parameter of the main() method is a one-dimensional array of Strings. Well, for C programmers, it might look like we are almost done with creating an array… But no..! We have just merely declared it, we have not allocated any memory yet.
There is another syntax by which we can declare arrays –

int array[];

This is looks almost like the C’s array declaration. But here, we don’t specify the size… Not yet..! But this style of declaration is considered to be ugly..! Oracle recommends that you use the previously discussed declaration syntax for declaring arrays.
Here are some other examples of legal declarations –

// One Dimensional Arrays
int[] intArray;             // Good
double[] doubleArray;

// One Dimensional Arrays
byte byteArray[];           // Ugly!
long longArray[];

// Two Dimensional Arrays
int[][] int2DArray;         // Good
double[][] double2DArray;

// Two Dimensional Arrays
byte[] byte2DArray[];       // Ugly
long[] long2DArray[];

And these are some examples of illegal declarations –

int[5] intArray;       // Don't mention size!
double{} doubleArray;  // Square Brackets please!

Instantiation

This is how we “instantiate”, or allocate memory for an array –

int[] array = new int[5];

When the JVM encounters the new keyword, it understands that it must allocate memory for something. And by specifying int[5], we mean that we want an array of ints, of size 5.
So, the JVM creates the memory and assigns the reference of the newly allocated memory to array which a “reference” of type int[]. Bit confusing isn’t it..? We can understand it better if we put the JVM’s job in a step-by-step process, but you’ll have to get used to the terminology –

  1. We create a reference of type int[], or, vaguely, we create a reference to an array of integers. The syntax is –
    int[] array;
    
  2. Then, we allocate the memory, or, create an object of type int[], or, we create an object of an array. In this step, we mention the size of the dimensions –
    int[] array = new int[5];
    int[][] bigArray = new int[5][5];
    
  3. Now, the JVM allocates the required memory an assigns the address of the newly allocated memory to the reference variable, or, object reference, the array variable. The array is initialized to the default value of the data type.

Let’s write a super simple code to practise the things we learnt so far. This program computes and stores the first 100 Fibonacci numbers –

public class SimpleFib {

    public static void main(String[] args) {
        int[] fib;              // Declaration
        fib = new int[100];     // Instantiation

        fib[0] = 1;
        fib[1] = 1;

        for (int i = 2; i < 100; ++i) {
            fib[i] = fib[i - 1] + fib[i - 2];
        }
    }

}

Note

Arrays in Java always know their sizes. The size of an array is available to you as the length property. You can use the dot operator ‘.’ on the object reference to access the length property. So, we can re-write the SimpleFib class using this feature –

public class SimpleFib {

    public static void main(String[] args) {
        int[] fib;              // Declaration
        fib = new int[100];     // Instantiation

        fib[0] = 1;
        fib[1] = 1;

        for (int i = 2; i < fib.length; ++i) {
            fib[i] = fib[i - 1] + fib[i - 2];
        }
    }

}

This is a more robust and maintenance free way of writing arrays with loops. This is a good practice and is recommended by many experienced programmers.

Initialization

  1. Using a Loop – Using a for loop to initialize elements of an array is the most common way to get the array going. There’s no need to run a for loop if you are going to assign the default value itself, because JVM does it for you.
  2. All in One..! – We can Declare, Instantiate and Initialize our array in one go. Here’s the syntax –
    int[] arr = {1, 2, 3, 4, 5};
    

    C programmers shouldn’t feel too weird about this syntax. Here, we don’t mention the size, because JVM can see that we are giving 5 values, so it says, “I’m not that dumb..!! 😛 ” … So the JVM does these bunch of things when it encounters such a statement –

    • Creates a variable named arr of type int[], that is, it becomes an array object reference variable.
    • Constructs an array object, or Instantiates, an int array of size 5.
    • Fills the newly constructed array with 1, 2, 3, 4, 5.
    • Assigns this array object to the array object reference variable, arr. A low level note…. It assigns the bit pattern corresponding to the memory allocated to the array. Well, you needn’t be too concerned about it. 😉

Anonymous Array

There is another “All in one..!” syntax to create arrays which is often called as an Anonymous Array. The syntax is –

int[] arr = new int[] {1, 2, 3, 4, 5};

Uh… What is this thing..? It looks like we added an additional “new int[]” to our previous version of “All in one..!” syntax. And we also know that the statement works fine even without that additional decoration.
Then why bother about this syntax at all..? This is handy in creating just-in-time arrays. Such requirement commonly arises when we are supposed to pass ever-changing values to a very frequently used function. Let’s assume you have a function that searches for some names in your phonebook and returns true if all the names were present. It would look like this –

public class AnonymousArray {

    public static void main(String[] args) {
       IsThere(new String[] {"Bill Gates", "Steve Jobs"});
       IsThere(new String[] {"James Gosling", "Ritchie"});
       IsThere(new String[] {"Emma Watson", "Emma Stone"});
    }

    static boolean IsThere(String[] names) {
        // Do some searching on something
        return true;    // if found, else false
    }

}

As you can see, you are frequently searching for names in your phonebook. Sometimes millionaires, or fathers of programming languages, or sometimes gorgeous actresses..! And based on whether the method returns true or false, you would like to take some action.
So, why exactly is Anonymous Arrays handy here..? Imagine you used the regular array syntax for the program –

public class RegularArray {

    public static void main(String[] args) {
        String[] millnrs = {"Bill Gates", "Steve Jobs"};
        String[] fathers = {"James Gosling", "Ritchie"};
        String[] actresses = {"Emma Watson", "Emma Stone"};

        IsThere(millnrs);
        IsThere(fathers);
        IsThere(actresses);
    }

    static boolean IsThere(String[] names) {
        // Do some searching on something
        return true;    // if found, else false
    }

}

Notice anything..? Well, it was just 3 arrays, so you may not notice anything. But imagine if you are creating a hundred such arrays..! They would all be lying in the memory with no purpose at all..! Plus… You’ll simply run out of names for the variables to create..! So, these two are the advantages of Anonymous Arrays in Java –

  • They don’t lie in the memory… Well, there are a special cases where they can. But generally using Anonymous Arrays for just-in-time requirements is a tidy business.
  • You don’t have to remember a lot names..! That is why they are called “anonymous”..!

Multidimensional Arrays in Java

Java treats multidimensional arrays literally as an “Array of Arrays”. You may not know what’s the little surprise behind that statement… So watch closely..!
These are some regular legal declarations for 2D arrays in Java –

int[][] arr2by2 = new int[2][2];
byte[][] arr2by3 = new byte[2][3];
short[][] arr0by2 = new short[0][2];

We all know how those arrays would look in the memory. Now, have a look at this two-dimensional array –

int[][] arr = new int[2][];

arr[0] = new int[2];
arr[1] = new int[3];

Well… You didn’t expect this did you..? 😛 … This is a really different way of creating a 2D array. In the memory, it would look like –
two-dimensional-array-in-java
You see how the array reference thing works..? The data types of the variables are shown by dotted arrows. The elements arr[0] and arr[1] become independent array references which can point to an array of any size. Hence, they point to different array objects which have arrays of different sizes. Important points to take away from the diagram are –

  • Array Objects (the oval shapes on the Heap) are created on the heap.
  • Array Object references of a particular dimension can point to an array object of the same dimension.Hence the following code is invalid –
    int[][] arr = new int[2][];
    
    arr[0] = new int[2][3];
    arr[1] = new int[3][4][5];
    

Methods in Arrays Class

There are a lot of predefined methods in the Arrays class absolutely ready to use..! In most of these methods, we must make sure that the objects are Comparable. A word of caution..! It is the “Arrays” Class, not “Array” Class… Be careful because there is an “Array” Class.

Method Signature Short Description
Arrays.sort(int[] array) Sorts the elements of the array in ascending order using Dual-Pivot Quicksort by Vladimir Yaroslavskiy, Jon Bentley, and Joshua Bloch. Has an good performance of O(N log N).
Arrays.sort(int[] array, int fromIndex, int toIndex) Sorts the elements of the array in the range [fromIndex, toIndex) into ascending order. Uses  the same Dual-Pivot Quicksort algorithm.
Arrays.binarySearch(int[] array, int key) Uses Binary Search algorithm to search for a key in the given array. Returns the index of the element if found, otherwise returns the index of the first element greater than the key. The array must be sorted in ascending order.
Arrays.binarySearch(int[] array, int fromIndex, int toIndex, int key) Uses Binary Search algorithm to search for a key in the given array in the range [fromIndex, toIndex). Has the same exact return values and requirements as the above version.
Arrays.copyOf(int[] array, int newLength) Returns a new Array which has the same elements as in the actual parameter array up to where the index is newLength. If newlength > array.length, then the extra elements are set to the default value of the respective data type.
Arrays.copyOfRange(int[] array, int fromIndex, int toIndex) Returns a new Array which has the same elements as in the actual parameter array, where index of the element in the parameter array is in the range [fromIndex, toIndex).
Arrays.equals(int[] array1, int[] array2) Returns true if both the arrays have the same elements in the same order.
Arrays.fill(int[] array, int value) Assigns value to all the elements of array.
Arrays.fill(int[] array, int fromIndex, int toIndex, int value) Assigns value to all the elements of array in the range [fromIndex, toIndex).

All these methods have overloaded versions to support all the primitive data types. To all those who don’t know overloading.. It means that you can use arrays of other data types with these functions… We will discuss overloading very soon..!

Some Pitfalls when using Arrays in Java

  1. Assigning One-Dimensional Arrays – We all know that JVM does a lot of automatic type conversion for us in the case of expressions involving variables of different numeric data types. Just a brief reminder that Java employs widening type conversion. Now, how about assigning a short array object to an int array object..?
    short[] shortArray = new short[10];
    int[] intArray = new int[5];
    
    intArray = shortArray;
    

    Well it seems to be fine.. But this gives a compilation error of “Incompatible Types”. The problem here isn’t that the sizes are different, but the issue is that a reference of type int[] can point to an object of int[], that is, an integer array, not any other.

  2. Assigning Two-Dimensional Arrays – The dimension of array, an array object reference can point to is fixed at the time of declaration and we cannot violate it. So, this code gives a compilation error –
    int[][] arr1 = new int[2][];
    int[][] arr2 = new int[3][2];
    
    arr1[0] = arr2;
    
  3. Array Size – There’s a small tricky thing with the array size. We generally don’t mess up this area, but it never harms to know. These are some legal array declarations –
    int[] arr = new int[0];
    int[][] arr = new int[0][2];
    

    Well, there’s nothing new… Even the GCC compiler wouldn’t bother about these pointless arrays. But, this is a legal array declaration in Java –

    short[] shortArray = new short[-1];
    

    Yes, it is legal… Legal, in the sense that the compiler won’t complaint… But you do get a runtime error saying, “NegativeArraySizeException”. The same thing in C would give a compilation error..!

Summary

  • This is how we declare and allocate memory (instantiate) for an array in Java –
    int[] array = new int[5];
    int[][] bigArray = new int[5][5];
    
  • The array elements are always initialized to the data type’s default value.
  • We can give our own initialization by –
    int[] arr = new int[] {1, 2, 3, 4, 5};
    
  • Arrays in Java always know their sizes. Every array object has a length attribute which is accessed by the dot operator –
    int[] arr = new int[5];
    System.out.println(arr.length);    // 5
    
  • We can create an anonymous array to implement some just-in-time logic by the syntax –
    function(new int[] {1, 2, 3, 4, 5});
    
  • Each element of a multidimensional array is an independant array reference. So, they can hold arrays of different sizes –
    int[][] arr = new int[2][];
    
    arr[0] = new int[2];
    arr[1] = new int[3];
    
  • The Arrays Class provides many useful methods to perform the regular operations on arrays easily and efficiently.
  • Even though Java employs widening type conversion between compatible data types, the following gives a compilation error –
    short[] shortArray = new short[10];
    int[] intArray = new int[5];
    
    intArray = shortArray;
    

Practise

  • Can you guess the output of this program..?
    public class ArraySizes {
    
        public static void main(String[] args) {
            int[][][] array1 = new int[1][3][5];
            int[][][][] array2 = new int[2][1][0][1];
    
            System.out.println(array1.length);
            System.out.println(array1[0].length);
            System.out.println(array1[0][1].length);
    
            System.out.println();
    
            System.out.println(array2.length);
            System.out.println(array2[1].length);
            System.out.println(array2[1][0].length);
    
            System.out.println();
    
            String[][][] str = new String[2][][];
    
            System.out.println(str.length);
            System.out.println(str[1]);
        }
    
    }
    

    Don’t run it…! 😛

This is all you need to know about arrays in Java to start writing programs of fairly good amount of complexity. I hope it helped you. If you have anything to ask about this topic, feel free to comment..! Keep practising..! Happy Coding..! 😀

Leave a Reply