Search code examples
javafor-looptoarray

Difference between printing array returned from toarray() method using enhanced for loop and traditional for loop


I have this code,

class Test
{
    public static void main(String args[])
    {
        ArrayList<Integer> al=new ArrayList<>();
        al.add(1);
        al.add(2);
        al.add(3);
        Integer a[]=new Integer[2];
        al.toArray(a);
        for(int i:a)
        System.out.println(i);
        /*for(int i=0;i<a.length;i++)
        System.out.println(a[i]);*/

    }
}

The above code throws NullPointerException but if I try to take the commented part off, and comment enhanced for loop it will print null 2 times. Printing a.length prints 2. Setting Integer array size to 3 will print 123.

Now correct me if I am wrong:

1> My understanding of toArray(T[] a) method is, if the size of the array is less than elements in the list, new array will be created with size specified by the array and elements in it will be null, considering this. my array should look like this a[]={null,null};

2> Difference between enhanced for loop and traditional for loop is that you can't modify or delete the individual element in enhanced for loop.

But, why is this different in this program? I am just printing them, why is enhanced for loop not printing null and throwing NullPointerException?


Solution

  • The toArray(a) method returns the converted array and that's what you should be using; it didn't use your array since it wasn't large enough.

    That is,

    1. if your list's size was 2 (the same as the length of the array you provided the method with) or
    2. if your array length was 3 (the same as the size of the list you wanted to convert into an array),

    you wouldn't have needed the returned array; and as such, your for loops would have printed what you wanted them to.

    As for the NullPointerException, it's because of the autounboxing it does from Integer to int. That is, the following code wouldn't have thrown an NPE:

    for(Integer i : a)
    {
      System.out.println(i);
    }
    

    while the following code will (as it did in your case):

    for(int i : a)
    {
      System.out.println(i);
    }
    

    As to why the compiler does the unboxing with the above enhanced for loop, think about it - the contents of the array are boxed integers. You try to assign them to a primitive int reference (read it as for every int in the array), so the only way to do it is unbox the boxed object.

    for(int i : a)
    {
      System.out.println(a[i]);
    }
    

    translates to

    for(int i = 0; i < a.length; i++)
    {
      System.out.println((int) a[i]);  // a[i] is null here, so casting causing an NPE
    }
    

    or even more correctly,

    for(int i = 0; i < a.length; i++)
    {
      System.out.println(a[i].intValue()); // a[i] is null here, causing an NPE
    }