代码改变世界

Effective Java 25 Prefer lists to arrays

2014-03-19 08:57  小郝(Kaibo Hao)  阅读(456)  评论(0编辑  收藏  举报

Difference

Arrays

Lists

1

Covariant

Invariant

2

Reified at runtime

Erased at run time

3

Runtime type safety

Compile time type safety

   

non-reifiable types

E, List<E> and List<String>

whose runtime representation contains less information than its compile-time representation.

Reifiable types

List<?> and Map<?,?>

Reverse to above.

   

This code fragment is legal:

// Fails at runtime!

Object[] objectArray = new Long[1];

objectArray[0] = "I don't fit in"; // Throws ArrayStoreException

   

but this one is not:

// Won't compile!

List<Object> ol = new ArrayList<Long>(); // Incompatible types

ol.add("I don't fit in");

   

Prohibition on generic array creation

  1. Not possible for a generic type to return an array of its element type.
  2. Not possible for using varargs methods in combination with generic types.( This is because every time you invoke a varargs method, an array is created to hold the varargs parameters. Use warning suppress to deal with it if it's required.).

       

None of these array creation expressions are legal:

new List<E>[],

new List<String>[] ,

new E[].

All will result in generic array creation errors at compile time.

   

// Why generic array creation is illegal - won't compile!

List<String>[] stringLists = new List<String>[1]; // (1)

List<Integer> intList = Arrays.asList(42); // (2)

Object[] objects = stringLists; // (3)

objects[0] = intList; // (4)

String s = stringLists[0].get(0); // (5)

   

Let's pretend that line 1, which creates a generic array, is legal. Line 2 creates and initializes a List<Integer>containing a single element. Line 3 stores the List<String>array into an Object array variable, which is legal because arrays are covariant. Line 4 stores the List<Integer>into the sole element of the Object array, which succeeds because generics are implemented by erasure: the runtime type of a List<Integer>instance is simply List, and the runtime type of aList<String>[]instance is List[], so this assignment doesn't generate an ArrayStoreException. Now we're in trouble. We've stored a List<Integer> instance into an array that is declared to hold only List<String>instances. In line 5, we retrieve the sole element from the sole list in this array. The compiler automatically casts the retrieved element to String, but it's an Integer, so we get a ClassCastExceptionat runtime. In order to prevent this from happening, line 1 (which creates a generic array) generates a compile-time error.

   

   

Use the Lists instead of the array to check the type safety at compile time

// List-based generic reduction

static <E> E reduce(List<E> list, Function<E> f, E initVal) {

List<E> snapshot;

synchronized(list) {

snapshot = new ArrayList<E>(list);

}

E result = initVal;

for (E e : snapshot)

result = f.apply(result, e);

return result;

}

   

Summary

If you find yourself mixing them and getting compile-time errors or warnings, your first impulse should be to replace the arrays with lists.