Skip to main content

Taming Tiger: The Collections Framework

Get a handle on the new collection types and additional features of existing classes and interfaces

John Zukowski (jaz@zukowski.net), President, JZ Ventures, Inc.
Author photo
John Zukowski conducts strategic Java consulting with JZ Ventures, Inc. and is working with SavaJe Technologies to develop a next-generation mobile phone platform. His latest books are The Definitive Guide to Java Swing, Third Edition (Apress, June 2005) and Mastering Java 2, J2SE 1.4 (Sybex, April 2002).

Summary:  You're probably quite familiar with the new Java™ 5 language support for generics, the concurrent utility libraries, and their effect on the Collections Framework, but those aren't the only changes to the Collections Framework libraries in Tiger. This month, John Zukowski covers several other enhancements, including the new collection types and the additional features of existing classes and interfaces.

View more content in this series

Date:  19 Jul 2005
Level:  Intermediate
Activity:  2839 views

The lion's share of interest in JDK 5.0 has been on the more prominent features of the Collections Framework, like the new language-level changes to support generics and the concurrent collections utility libraries found in the java.util.concurrent package. In fact, prior developerWorks content covered just that in "Concurrent collections" and the "Introduction to generic types in JDK 5.0" tutorial. But other enhancements haven't been given nearly enough attention. In this article, I'll look at three other changes: the updated Arrays and Collections classes and the new Queue interface, with its PriorityQueue implementation.

Arrays

The Arrays class provides a series of static utility methods for working with arrays, those indexed data structures that are of a fixed size. Prior to 5.0, the class had binarySearch(), equals(), fill(), and sort() methods for each of the different array types you could have for primitive data types and a generic Object type. An additional asList() method for converting an Object array to a List is still available. Tiger adds to the set with hashCode() and toString() for all and deepEquals(), deepHashCode(), and deepToString() methods specific to Object arrays. In total, 21 new methods are available:

  • public static boolean deepEquals(Object[] a1, Object[] a2)
  • public static int deepHashCode(Object[] a)
  • public static String deepToString(Object[] a)
  • public static int hashCode(boolean[] a)
  • public static int hashCode(byte[] a)
  • public static int hashCode(char[] a)
  • public static int hashCode(double[] a)
  • public static int hashCode(float[] a)
  • public static int hashCode(int[] a)
  • public static int hashCode(long[] a)
  • public static int hashCode(Object[] a)
  • public static int hashCode(short[] a)
  • public static String toString(boolean[] a)
  • public static String toString(byte[] a)
  • public static String toString(char[] a)
  • public static String toString(double[] a)
  • public static String toString(float[] a)
  • public static String toString(int[] a)
  • public static String toString(long[] a)
  • public static String toString(Object[] a)
  • public static String toString(short[] a)

This change to the utility class is the first since the Collections Framework debuted in J2SE 1.2. I'm not sure why Sun waited so long to introduce the changes, but they are welcome additions to the series of available helper methods.

The first of the new methods added is hashCode(). For any array type, you can call Arrays.hashCode(arrayVar) and get a well formed hash code. This hash code could be used as a key into a HashMap or for any other related purpose. Unless you know how to generate a good hash code, the one generated from the Arrays class is bound to be better, resulting in fewer collisions. It happens to generate a code that is equivalent to having a List of the same elements.

When creating your own classes, you are supposed to provide both equals() and hashCode() methods together. With the help of the new hashCode() method of Arrays, you can use it to generate a hash code for any local array types, instead of rolling your own each time you need it.

The other method that is now available for all array types is toString(). For any array type, you can call Arrays.toString(arrayVar) to get a comma-separated list of elements, surrounded by square brackets, as shown by the program in Listing 1:


Listing 1. Stringifying with Arrays.toString

import java.util.Arrays;

public class ArgsToString {
  public static void main(String args[]) {
    System.out.println(Arrays.toString(args));
  }
}

Listing 2 shows the results:


Listing 2. Results from Listing 1

>java ArgsToString One Two Three
  [One, Two, Three]

The new deepEquals(), deepHashCode(), and deepToString() methods work like their non-deep counterparts, but instead of stopping and working with each element of the top-level array, they continue to dig deeper into the multi-dimensional array to generate results.

While not a new method, the asList() method does actually behave differently with 5.0. Previously, the method accepted an Object[] array as its argument. Now, because of the variable-argument list features of Tiger, any comma-separated list will work, as shown in Listing 3:


Listing 3. Arrays.asList differences

import java.util.Arrays;

public class AsList {
  public static void main(String args[]) {
    // Before
    List before = Arrays.asList(args);
    // After
    List after = Arrays.asList("One", "Two", "Three");
  }
}

The two examples in Listing 3 won't necessarily produce the same results if the elements passed to the command-line are different, but it does show how the language-level changes of Tiger extend the functionality of the original asList() method of Arrays.


Collections

The complementary class of Arrays for the different collections is the Collections class. Again, the class isn't new, but the features of the class have been extended for 5.0. You now have 13 new methods:

  • checkedCollection()
  • checkedSet()
  • checkedSortedSet()
  • checkedList()
  • checkedMap()
  • checkedSortedMap()
  • emptySet()
  • emptyList()
  • emptyMap()
  • reverseOrder()
  • frequency()
  • disjoint()
  • addAll()

The six checked*() methods work similar to the six synchronized*() and unmodifiable*() methods. With the synchronized*() methods, you provide a collection to the method and are given back a synchronized, thread-safe version of that same collection. With unmodifiable*(), you get back a read-only view of the specified collection. The checked*() operation requires a second and possibly third argument, in addition to the collection (as shown in Listing 4), and returns a dynamically typesafe view of the collection:


Listing 4. Checked collections

  public static <E> Collection<E> checkedCollection(
    Collection<E> c, Class<E> type)
  public static <E> Set<E> checkedSet(
    Set<E> s, Class<E> type)
  public static <E> SortedSet<E> checkedSortedSet(
    SortedSet<E> s, Class<E> type)
  public static <E> List<E> checkedList(
    List<E> list, Class<E> type)
  public static <K,V> Map<K,V> checkedMap(
    Map<K,V> m, Class<K> keyType, Class<V> valueType)
  public static <K,V> SortedMap<K,V> checkedSortedMap(
    SortedMap<K,V> m, Class<K> keyType, Class<V> valueType)

With the Java 5.0 platform, you would think that because you declared a collection as generic (Collection<String> c = new HashSet<String>();), you wouldn't need run-time type checks, but if you were to pass your String version of HashSet to a utility method that only works with a non-generic Set, then that method could incorrectly add a non-String element to the set. Temporarily modifying the program to add the run-time check with Collection<String> c = Collections.checkedCollection(new HashSet<String>(), String.class); enables you to find the source of the problem quickly.

The three empty*() methods -- emptySet(), emptyList(), and emptyMap()-- generate empty immutable collections. While you can certainly create empty collections with method calls like new ArraySet(), that collection would then need to go through one of the unmodifiable*() methods to make sure the new collection was immutable. The empty methods provide empty, read-only collections in a more optimal way.


Queue interface

One of the bigger changes to the 5.0 Collections Framework is the addition of the new base interface Queue. While described in the "Concurrent Collections" tip (see Resources), the use of the interface is not limited to concurrency. In computer science, a queue data structure is your basic first-in, first-out (FIFO) structure. Items are added to the end and removed from the beginning. Not only do you add and remove elements, you can also look at the queue to see what is there. Listing 5 shows the five methods of the Queue interface:


Listing 5. The Queue interface
  public boolean offer(Object element)
  public Object remove()
  public Object poll()
  public Object element()
  public Object peek()

Keep in mind that Queue extends from the Collection interface, so implementations of the Queue interface also implement Collection. When using an implementation of Queue, you should try to limit yourself to methods of the interface. For instance, adding elements to a Queue could be done with the add() method of Collection, throwing an unchecked exception on failure. Instead, if a sized queue was full, the offer() method returns false, not causing you to deal with exceptions when full.

Several implementations of the Queue interface exist in the java.util.concurrent package, but not all of them. The LinkedList class has been retrofitted with the Queue interface with JDK 5.0 and the PriorityQueue has been added with JDK 5.0. The remaining implementations -- ArrayBlockingQueue, ConcurrentLinkedQueue, DelayQueue, LinkedBlockingQueue, PriorityBlockingQueue, and SynchronousQueue -- are all part of the java.util.concurrent package.

Because LinkedList isn't new, let's look at the new PriorityQueue class. As shown in Listing 6, you can create one in six ways. When a Comparator isn't available, the natural ordering of the elements is used to determine priority. If the elements don't implement the Comparable interface, then that is a run-time error:


Listing 6. PriorityQueue constructors
  PriorityQueue() 
  PriorityQueue(Collection<? extends E> c) 
  PriorityQueue(int initialCapacity) 
  PriorityQueue(int initialCapacity, Comparator<? super E> comparator) 
  PriorityQueue(PriorityQueue<? extends E> c) 
  PriorityQueue(SortedSet<? extends E> c) 

To demonstrate the use of PriorityQueue, the program in Listing 7 adds all the command line elements and processes them in alphabetical order. Had the queue structure been a LinkedList, the order would have been the more typical FIFO order, but a PriorityQueue relies on priorities to order elements:


Listing 7. PriorityQueue usage
import java.util.*;
import java.util.concurrent.*;

public class Priority {
  public static void main(String args[]) {
    Queue<String> queue =
      new PriorityQueue<String>(Arrays.asList(args));
    String element;
    while ((element = queue.poll()) != null) {
	    System.out.println(element);
    }
  }
}

Listing 8 shows the output of running the program with a command line of one two three four:


Listing 8. Results from Listing 7

>java Priority one two three four
  four
  one
  three
  two

One thing to mention about the new Queue interface, with relation to the Collections class: Methods checkedQueue(), emptyQueue(), synchronizedQueue(), and unmodifiableQueue() are all missing from the Collections class. According to bug reports, all cases but checkedQueue() were done purposely. For synchronizedQueue(), the concurrent collections are better alternatives then a mere wrapper. The others were deemed unnecessary. Perhaps checkedQueue() (and checkedBlockingQueue()) will be added with the Tiger/6.0 release.



Download

DescriptionNameSizeDownload method
Sample codej-tiger07195-source.zip1 KB HTTP

Information about download methods


Resources

About the author

Author photo

John Zukowski conducts strategic Java consulting with JZ Ventures, Inc. and is working with SavaJe Technologies to develop a next-generation mobile phone platform. His latest books are The Definitive Guide to Java Swing, Third Edition (Apress, June 2005) and Mastering Java 2, J2SE 1.4 (Sybex, April 2002).

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology
ArticleID=89019
ArticleTitle=Taming Tiger: The Collections Framework
publish-date=07192005
author1-email=jaz@zukowski.net
author1-email-cc=jaloi@us.ibm.com

My developerWorks community

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere).

My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Rate a product. Write a review.

Special offers