1 June 2010

literal arrays and lists in Java

In Python and other modern languages, you can say things like:
for x in ['cat', 'window', 'defenestrate']:
    print x, len(x)
In Java, there is no direct syntax for array or list literals. The only thing that Java has are “Array Initializers” that can be used right where an array is declared. Thus the above Python code becomes:
String[] xs = {"cat", "window", "defenestrate"};
for (String x : xs)
    System.out.println(x);

For people who need a lot of literal arrays, this can be a bother, especially when you need small arrays on the inside of expressions. Fortunately, Java's new “variable length argument lists” can help here, because they transform any number of arguments into just.... an array. So this little helper function does the job:

static  T[] array(T... elems)
{
    return elems;
}

Now I can happily write:
for (String x : array("cat", "window", "defenestrate")) 
       System.out.println(x);

Java's standard library even provides a function to create literal lists. Ironically this function is placed in class Arrays although it neither eats nor produces an array.

public static  List asList(T... a)

The nice thing about this factory method is that it provides a list which is backed by an array, so you get a list of fixed size – that saves a little bit of memory and can be useful in some situations. Unfortunately, the documentation says nothing about what happens when you call size-changing methods (like add()) on the resulting list. It's a typical omission of the Java documentation. One has to figure out all the details by oneself. Unfortunately, many Java programmers don't even know that there are such details and then they are surprised when it hits them.

I just did a quick history research. It seems that the helpful function asList(...) exists in Java at least since 1998 (Java 1.2, with the Collections framework). Given that Java really became famous around and after this time, it is really deplorable, that most Java tutorials introduce lists like this:
List ls = new ArrayList();
ls.add(1);
ls.add(2);
for ( Integer i : ls )
    // do stuff

When they instead could write:

for ( Integer i : Arrays.asList(1, 2) )
    // do stuff

Admittedly, the “for ( i : ls )” syntax and variables length argument lists have only been deployed with Java 1.5 in 2004. Curiously, the simplified for loop has become widespread already, while varargs and list literals haven't.

Update: I was about to edit my program to make use of the simplified syntax when I discovered, that Java has anonymous array literals after all. I used Ecplise's “inline local variable” refactoring to get rid of the array dummy and what it produced was:
    return new Object[] {1, 2, 3};

Curious again: the feature is there (probably even since an early release), but people don't know about it!

5 comments:

Gilles Duboscq said...

Also, there's collection litterals which should make it into JDK7 (see the proposal at http://mail.openjdk.java.net/pipermail/coin-dev/2009-March/001193.html)

Henrik said...

I'm a bit late to the party, but I just thought I could point out that the reason why asList(T... a) is placed in Arrays is just because it takes an array. Java's variable length argument lists are nothing but syntactic sugar for an array.

Ajoy Bhatia said...

Although Arrays.asList(...) exists since 1998, varargs only came much later. Also, Java does not have arrays of primitives - only arrays of Objects - and another thing that came later is autoboxing of literals into objects. So, at that time, you could not write:
Arrays.asList(1, 2)

You would have had to write:
Arrays.asList( new Integer[ ] { new Integer(1), new Integer(2), new Integer(3) } )

Yes, that is shorter than the multiple ls.add(...) statements but much harder for a Java beginner, the person for whom the tutorial was written.

Unknown said...
This comment has been removed by a blog administrator.
Unknown said...

Thanks, it was very useful!

Post a Comment