5

Purpose : Array.length gives us storage initialized to array. But wanted to find out count of non-null elements stored in array out of total storage initialized. I know many approaches are possible but here question is related to approach which I used.

Since ArrayList has a size() method which gives us count of actual elements stored regardless of total storage initialized.

So, I thought of converting array to ArrayList and finding out the size. Hence I used Arrays.asList(a).size() as shown below:

public class Driver {

    public static void main(String []args)
    {
        int a[] = new int[10];
        a[0]=30;
        a[1]=100;
        a[2]=33;
        System.out.println((Arrays.asList(a)).size() );
    }

Strangely , it returns result as 1 regardless of the a[0], a[1], a[2].

Same steps if we do with ArrayList instead of Array gives us result 3:

{
    List<Integer> temp = new ArrayList<Integer>(20); 
    System.out.println(temp.size()); 
    temp.add(20); 
    temp.add(40); 
    System.out.println(temp.size()); 
}

Result is 0 2.

Question: Should be agree that something is wrong with asList API of Arrays utitlity like bug or limitation?

Remarks: Looking at internal implementation, I understand that asList invokes constructor of ArrayList:

  public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        size = elementData.length;
        .....
  }

It again invokes the collection's toArray. But then not sure why we are getting answer as 1 since elementData.length should have stored in size value 10?

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
DPKGRG
  • 65
  • 1
  • 5
  • What does "Same steps if we do with ArrayList instead of Array gives us result 3." mean? How do you do those other steps? Where do you use Array? – Mad Physicist Sep 06 '18 at 05:47
  • When i said Same steps, i meant following which gives result 0 and 2 : List temp = new ArrayList(20); System.out.println(temp.size()); temp.add(20); temp.add(40); System.out.println(temp.size()); – DPKGRG Sep 06 '18 at 05:48
  • 1
    "Strangely , it returns result as 1 regardless". No, it returns 10. Primitives can't be null. Primitive arrays are automatically zeroed out. Zero is not null. – Mad Physicist Sep 06 '18 at 05:48
  • Please edit your question with that code and fix the typos that make it very difficult to understand what you mean. – Mad Physicist Sep 06 '18 at 05:49
  • Possible duplicate of [Arrays.asList() not working as it should?](https://stackoverflow.com/questions/1467913/arrays-aslist-not-working-as-it-should) – benjamin c Sep 06 '18 at 06:31

4 Answers4

3

There are three very different concepts that you are somehow attempting to equate here.

First there's null elements in a list or array. null is a perfectly valid value to have in either. It is not the same as being uninitialized. In fact, arrays of any non-primitive type are explicitly initialized to null by default.

Then there are unused elements in a list. When you do

ArrayList<Integer> a = new ArrayList<>(20);
a.add(null);

you will have a List of size 1. null is a totally valid reference to stick in a list, and the capacity has nothing to do with the size. The 20 you passed to the constructor is just a hint not to reallocate memory until you've inserted 20 actual elements into the list. Those 19 other elements are not null. They literally don't exist.

Third, there is the issue of primitive arrays. When you create a primitive array, it will have a fixed length and every element contains a valid value. By default, arrays are zeroed out with false, 0, 0L, 0.0f, 0.0, or whatever is appropriate for the type. Your code creates an array with three non-zero elements and seven zeros. Primitives are not references, so can never be null. Even if they could, making a List from a 10 element array would give you a size of 10.

Your attempt at creating an ArrayList is in no way equivalent to applying Arrays.asList(), even if that were to work. Creating a list and adding three elements to it will make a list of size three. On top of that, keep in mind that a List can only hold references, in your case to the boxed type Integer. An Integer reference can be null and still be a valid list item, but can't be unboxed into a primitive value.

Finally, you can't convert an array of primitives into a list using asList. asList accepts varargs, rather than a single list, which is why you always end up with one element list. The problem here is actually that you have a list of primitives: an array of references would be expanded just fine. An alternative in Java 8 is

List<Integer> list = Arrays.stream(ints).boxed().collect(Collectors.toList());

Notice the explicit boxing operation. The size of your list will still be 10, not 3.

Reference: How to convert int[] into List<Integer> in Java?

Mad Physicist
  • 107,652
  • 25
  • 181
  • 264
2

You get 1 because Arrays.asList(int[] a) returns List<int[]>, not List<Integer>. The way you're using method asList() is incorrect. If you would like to get List<Integer> instead, you should pass the contents of array to method asList() one by one.
List<Integer> list = Array.asList(30, 100, 33);
There is no direct method to convert an array into List on the fly

mangusta
  • 3,470
  • 5
  • 24
  • 47
  • agree that "no direct method to convert an array into List" and the above is a wrong usage of asList. – DPKGRG Sep 06 '18 at 06:05
  • @MadPhysicist right! I didn't follow Java 8. OP, for direct conversion, please refer to the link provided – mangusta Sep 06 '18 at 06:18
  • In addition to MadPhysicist's input, if you only want to know the number of elements in your array A; just use the count function of the stream API: `Arrays.stream().count()`. – KarelG Sep 06 '18 at 06:37
0

There is no direct method to get List from Array...!!!
Yes above sentence is partially correct.
If your array is of primitive type the it creates an List containing whole array as first element of newly created List.

Like:

public static void main(String[] args) {
    int a[] = new int[10];
    a[0] = 30;
    a[1] = 100;
    a[2] = 33;
    List list = Arrays.asList(a);
}

List if int Array

But if your array is of any reference type then it create with each element of passed array as a list element.

public static void main(String[] args) {
    Object a[] = new Object[10];
    a[0] = 30;
    a[1] = 100;
    a[2] = 33;
    List list = Arrays.asList(a);
}

List Of Objects

That's why in your case it shows only one element in size.

This behavior is because of implementation of asList() which calls ArrayList constructor directly.

public static <T> List<T> asList(T... a) {
    return new ArrayList<>(a);
}
Sunil Kanzar
  • 1,244
  • 1
  • 9
  • 21
0
public class Test {

    public static void main(String []args)
    {
        Integer a[] = new Integer[10];
        a[0]=30;
        a[1]=100;
        a[2]=33;
        //List<Integer> list=Arrays.asList(a);
        System.out.println(Arrays.asList(a).size() );
    }
}

Output

10

Use wrapper classes, and there is your solution. Streams aren't quite performant as you expect (as of now).

Mohammad
  • 21,175
  • 15
  • 55
  • 84