39

I'm new to Java and am trying to understand why the first code snippet doesn't cause this exception but the second one does. Since a string array is passed into Arrays.asList in both cases, shouldn't both snippets produce an exception or not produce an exception?

Exception in thread "main" java.lang.ClassCastException: java.util.Arrays$ArrayList cannot be cast to java.util.ArrayList

First snippet (causes no exception):

ArrayList<ArrayList<String>> stuff = new ArrayList<ArrayList<String>>();
String line = "a,b,cdef,g";
String delim = ",";
String[] pieces = line.split(delim);
stuff.add((ArrayList<String>) Arrays.asList(pieces));

Second snippet (causes above exception):

ArrayList<ArrayList<String>> stuff = new ArrayList<ArrayList<String>>();
String[] titles = {"ticker", "grade", "score"};
stuff.add((ArrayList<String>) Arrays.asList(titles));

If relevant, I'm using JavaSE 1.6 in Eclipse Helios.

DannyTree
  • 1,137
  • 2
  • 12
  • 16
  • 2
    I'm on IBM JDK and for me even your first snippet gives the same error! – adarshr Jul 10 '11 at 12:18
  • 1
    Thanks for all your answers. Each answer had helpful information and is helping me to better understand Java and a reminder to use good coding style. – DannyTree Jul 10 '11 at 12:35

7 Answers7

31

For me (using Java 1.6.0_26), the first snippet gives the same exception as the second one. The reason is that the Arrays.asList(..) method does only return a List, not necessarily an ArrayList. Because you don't really know what kind (or implementation of) of List that method returns, your cast to ArrayList<String> is not safe. The result is that it may or may not work as expected. From a coding style perspective, a good fix for this would be to change your stuff declaration to:

List<List<String>> stuff = new ArrayList<List<String>>();

which will allow to add whatever comes out of the Arrays.asList(..) method.

Waldheinz
  • 10,399
  • 3
  • 31
  • 61
  • 2
    This answer is the one that helped me understand what the other answers were saying about coding to an interface rather than to an implementation and how my casting was unsafe. – DannyTree Jul 10 '11 at 12:33
  • Good explanation. Another simple solution below in this page. – GFPF Jan 25 '16 at 08:48
10

If you do this, you won't get any CCE:

ArrayList<ArrayList<String>> stuff = new ArrayList<ArrayList<String>>();
String[] titles = {"ticker", "grade", "score"};
stuff.add(new ArrayList<String>(Arrays.asList(titles)));

As the error clearly states, the class java.util.ArrayList isn't the same as nested static class java.util.Arrays.ArrayList. Hence the exception. We overcome this by wrapping the returned list using a java.util.ArrayList.

adarshr
  • 61,315
  • 23
  • 138
  • 167
  • Thanks, @adarshr. I had discovered that but forgot to post it in my question. I'm still curious as to the cause of the exception. – DannyTree Jul 10 '11 at 12:18
  • I think this answer is more relevant because Arrays$ArrayList represents an inner class ArrayList defined in Arrays class. – MohamedSanaulla Mar 18 '13 at 17:14
10

The problem is you specified your List to contain ArrayLists - and by implication no other List implementations. Arrays.asList() returns its own implementation of a List based on the implementation of the array parameter, which may not be an ArrayList. That's your problem.

More broadly, you have a classic code style problem: You should be referring to abstract interfaces (ie List), not concrete implementations (ie ArrayList). Here's how your code should look:

List<List<String>> stuff = new ArrayList<List<String>>();
String[] titles = { "ticker", "grade", "score" };
stuff.add((List<String>) Arrays.asList(titles));

I have tested this code, and it runs without error.

Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • how do you determine to use new ArrayList> rather than new List> or new List>? – DannyTree Jul 10 '11 at 12:24
  • 1
    @DannyTree The Java `new` keyword creates a new instance of a class. To do so, the class has to be "concrete" (as in "not abstract"). This basically means that it may not have "loose ends", all methods must have implementations. When you say `new List>`, you don't specify *which kind* of `List` you want to instantiate, so this does not work. – Waldheinz Jul 10 '11 at 12:38
8

No need to cast manually. This simple code may help you,

List stuff = new ArrayList();
String line = "a,b,cdef,g";
String delim = ",";
stuff.addAll(Arrays.asList(line.split(delim)));
Srinivasan.S
  • 3,065
  • 1
  • 24
  • 15
1

If you want to use your property as ArrayList<'T'> you need only declare there and create a getter.

    private static ArrayList<String> bandsArrayList;

    public ArrayList<String> getBandsArrayList() {
        if (bandsArrayList == null) {
            bandsArrayList = new ArrayList<>();

            String[] bands = {"Metallica", "Iron Maiden", "Nirvana"};
            bandsArrayList.addAll(Arrays.asList(bands));
        }
        return bandsArrayList;
    }

Initializes the variable and use the method [addAll (Collection collection)](http://developer.android.com/intl/pt-br/reference/java/util/ArrayList.html#addAll(java.util.Collection))

GFPF
  • 959
  • 14
  • 19
1

Using a debugger, I determined that Array.asList(titles) returns an "Arrays$ArrayList" (ie an inner class of the Arrays class) rather than a java.util.ArrayList.

It's always best to use the interface on the left side of expressions, in this case List rather than the concrete ArrayList. This works fine:

    List<List<String>> stuff = new ArrayList<List<String>>();
    String[] titles = {"ticker", "grade", "score"};
    stuff.add((List<String>) Arrays.asList(titles));
Ant Kutschera
  • 6,257
  • 4
  • 29
  • 40
0

First, Arrays.asList() should be never casted to ArrayList. Second, since generics were introduced into java programming language casting is still relevant when using legacy, pre-generics APIs.

Third, never use concrete classes at the left of assignment operator.

Bottom line, say

List<List<String>> stuff = new ArrayList<List<String>>();
String line = "a,b,cdef,g";
String delim = ",";
String[] pieces = line.split(delim);
stuff.add(Arrays.asList(pieces));



List<List<String>> stuff = new ArrayList<List<String>>();
String[] titles = {"ticker", "grade", "score"};
stuff.add(Arrays.asList(titles));

and be happy.

AlexR
  • 114,158
  • 16
  • 130
  • 208