Collection Interface vs arrays
We are learning about the Collection Interfac开发者_高级运维e and I was wondering if you all have any good advice for it's general use? What can you do with an Collection that you cannot do with an array? What can you do with an array that you cannot do with a Collection(besides allowing duplicates)?
The easy way to think of it is: Collections beat object arrays in basically every single way. Consider:
- A collection can be mutable or immutable. A nonempty array must always be mutable.
- A collection can allow or disallow null elements. An array must always permit null elements.
- A collection can be thread-safe; even concurrent. An array is never safe to publish to multiple threads.
- A list or set's
equals
,hashCode
andtoString
methods do what users expect; on an array they are a common source of bugs. - A collection is type-safe; an array is not. Because arrays "fake" covariance,
ArrayStoreException
can result at runtime. - A collection can hold a non-reifiable type (e.g.
List<Class<? extends E>>
orList<Optional<T>>
). An array will generate a warning for this. - A collection can have views (unmodifiable, subList...). No such luck for an array.
- A collection has a full-fledged API; an array has only set-at-index, get-at-index, length and clone.
- Type-use annotations like
@Nullable
are very confusing with arrays. I promise you can't guess what@A String @B [] @C []
means. - Because of all the reasons above, third-party utility libraries should not bother adding much additional support for arrays, focusing only on collections, so you also have a network effect.
Object arrays will never be first-class citizens in Java APIs.
A couple of the reasons above are covered -- but in much greater detail -- in Effective Java, Third Edition, Item 28, from page 126.
So, why would you ever use object arrays?
- You're very tightly optimizing something
- You have to interact with an API that uses them and you can't fix it
- so convert to/from a
List
as close to that API as you can
- so convert to/from a
- Because varargs (but varargs is overused)
- so ... same as previous
- Obviously some collection implementations must be using them
- I can't think of any other reasons, they suck bad
It's basically a question of the desired level of abstraction.
Most collections can be implemented in terms of arrays, but they provide many more methods on top of it for your convenience. Most collection implementations I know of for instance, can grow and shrink according to demand, or perform other "high-level" operations which basic arrays can't.
Suppose for instance that you're loading strings from a file. You don't know how many new-line characters the file contains, thus you don't know what size to use when allocating the array. Therefore an ArrayList is a better choice.
The details are in the sub interfaces of Collection, like Set, List, and Map. Each of those types has semantics. A Set typically cannot contain duplicates, and has no notion of order (although some implementations do), following the mathematical concept of a Set. A List is closest to an Array. A Map has specific behavior for push and get. You push an object by its key, and you retrieve with the same key.
There are even more details in the implementations of each collection type. For example, any of the hash based collections (e.g. HashSet, HasMap) are based on the hashcode() method that exists on any Java object.
You could simulate the semantics of any collection type based of an array, but you would have to write a lot of code to do it. For example, to back a Map with an array, you would need to write a method that puts any object entered into your Map into a specific bucket in the array. You would need to handle duplicates. For an array simulating a Set, you would need to write code to not allow duplicates.
The Collection interface is just a base interface for specialised collections -- I am not aware yet of a class that simply just implements Collection; instead classes implement specialized interfaces which extend Collection. These specialized interfaces and abstract classes provide functionality for working with sets (unique objects), growing arrays (e.g. ArrayList), key-value maps etc -- all of which you cannot do out of the box with an array. However, iterating through an array and setting/reading items from an array remains one of the fastest methods of dealing with data in Java.
One advantage is the Iterator interface. That is all Collections implement an Iterator. An Iterator is an object that knows how to iterate over the given collection and present the programmer with a uniformed interface regardless of the underlying implementation. That is, a linked list is traversed differently from a binary tree, but the iterator hides these differences from the programmer making it easier for the programmer to use one or the other collection.
This also leads to the ability to use various implementations of Collections interchangeably if the client code targets the Collection interface iteself.
精彩评论