0

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?

Gpar
  • 181
  • 1
  • 1
  • 7
  • You need to use the return value of `toArray(a)`, not the passed in value. Note in the documentation for "Parameters" where it says: "a - the array into which the elements of this collection are to be stored, if it is big enough; otherwise, a new array of the same runtime type is allocated for this purpose". https://docs.oracle.com/javase/7/docs/api/java/util/Collection.html#toArray%28T[]%29 – clstrfsck Nov 17 '14 at 00:18

2 Answers2

1

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
}
mystarrocks
  • 4,040
  • 2
  • 36
  • 61
  • 1> what is autounboxing? I am aware of autoboxing and unboxing. 2> Is autounboxing doesn't happen with traditional for loop? 3> Another answer to this query says my array a will be of size 3. Am I wrong in understanding toArray() method? – Gpar Nov 17 '14 at 06:46
  • By `autounboxing` I really meant the `unboxing` that `compiler` does on your behalf. The point 2> you made is exactly why I called it `autounboxing` - the compiler does it for you; you don't do it in the case you showed. And on 3> I meant that your array length should at least have been `3`, i.e `Integer[] a = new Integer[3]`. – mystarrocks Nov 17 '14 at 13:20
  • Thanks @mystarrocks my 1st and 2nd points are clear. my 3rd point was based on toArray() method specification in JLS. According to which array a will be created newly as size of collection and array are different and size of the array is smaller than that of collection. Is this new array will be of size specified by the collection or specified by the array? i.e in my program a will be of size 3 or 2? – Gpar Nov 18 '14 at 19:55
  • Another answer by another person to my same query says array size will be 3. But no, my array size if printed says its 2. – Gpar Nov 18 '14 at 20:07
  • In your program, the size of `a` was and will ever be `2`, which is what the problem is. Its size should have been `3` to fit all the elements in your source collection, i.e the list. That is why the `.toArray` method is forced to create a new array of length `3` (to fit all your elements from the source list). To summarize, the length of `a` will be `2` and the length of the returned array from the `toArray` method will be `3`. – mystarrocks Nov 18 '14 at 20:08
  • I got you now. Thank you. – Gpar Nov 19 '14 at 08:18
0
public <T> T[] toArray(T[] a)

It takes array as parameter to copy all the elements and returns that array. If your array is large enough then it copy on that otherwise same new array at runtime is allocated for this purpose. In your case, a is of size 2. so new array a of size 3 is created runtime and values are copied to this new array and returned.

2nd thing you are printing a[i] instead of i. since i is containing element value so print i.

something like this:

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];
    a=al.toArray(a);
    for(Integer i:a) //or for(int i:a)
    System.out.println(i);
}
kriyeta
  • 695
  • 4
  • 12