Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

Magic with Merlin: Maintaining insertion order

Working with the new linked HashSet and HashMap implementations

John Zukowski (jaz@zukowski.net), President, JZ Ventures, Inc.
Author photo
John Zukowski conducts strategic Java consulting with JZ Ventures, Inc. and serves as the resident guru for a number of jGuru's community-driven Java FAQs. His latest books are Java Collections and Definitive Guide to Swing for Java 2 (2nd ed) from Apress. Contact John at jaz@zukowski.net.

Summary:  Follow along with John Zukowski as he demonstrates how to iterate through the elements of a hashed collection in insertion order and how to maintain elements in access order with the new Collections Framework implementations in J2SE, version 1.4.

View more content in this series

Date:  01 Aug 2001
Level:  Introductory
Also available in:   Japanese

Activity:  14264 views
Comments:  

J2SE 1.4 introduces two new implementations to the Java Collections Framework, LinkedHashSet and LinkedHashMap. The advantage of these additions is that a hashed collection now maintains two paths through its elements. In addition to the standard hashing relationship, there is now a linked list that traverses through the collection. Under normal circumstances, this new second path would follow the insertion order, meaning that the iterator for the collection will return the elements in their insertion order (not in the order that their hashing codes have them incorporated into the collection), but LinkedHashMap supports a second ordering option: maintaining the linked list in access order instead of insertion order.

Let's take a look at how these new classes work.

Getting started

Getting started with these new classes is easy. Just import the java.util package and find a set of items to work with. For our example, we'll use calendar months. We'll use with the English months when working with the set, and English and Italian names when working with the map.

import java.util.*;
public class OrderedAccess {
  public static void main(String args[]) {
    String months[] = 
      new DateFormatSymbols().getMonths();
    String italianMonths[] = 
      new DateFormatSymbols(Locale.ITALIAN).getMonths();
  }
}

I'll assume you already know the names and order of the months in English. For those of you who aren't familiar with the Italian month names, they are: Gennaio, Febbraio, Marzo, Aprile, Maggio, Giugno, Luglio, Agosto, Settembre, Ottobre, Novembre, and Dicembre, though for some reason getMonths() returns the names not capitalized.


Using the new HashSet

The LinkedHashSet is a subclass of the basic HashSet class. Thus, everything you can do with HashSet, you can do with LinkedHashSet. There are no new methods in the class. All you get are the four constructors:

  • LinkedHashSet()
  • LinkedHashSet(Collection c)
  • LinkedHashSet(int initialCapacity)
  • LinkedHashSet(int initialCapacity, float loadFactor)

To add elements to a set, we can either call add() for each element, or create a Collection and pass that to the constructor. Because we have the elements in an array, the simplest mechanism is to use Arrays.asList(), which will return the array wrapped into a List, maintaining the order from the original array. By passing the list on to the constructor, we can easily add the same list to both a LinkedHashSet and a plain HashSet.

  List list = Arrays.asList(months);
  Set orderedSet = new LinkedHashSet(list);
  Set unorderedSet = new HashSet(list);

After filling up our sets, we can examine their elements to see if the linked set maintained its elements in insertion order, and then compare the results to the standard hash set. You can either iterate through each set manually, through its iterator(), or just call the toString() method (implicitly), which essentially just does that for us.

  System.out.println("Ordered:   " + orderedSet);
  System.out.println("Unordered: " + unorderedSet);

The ordered set displays as follows:

Ordered:   [January, February, March, April, May, June, July, August, 
  September, October, November, December, ]

While the unordered set displays as:

Unordered: [March, April, November, October, January, July, September, 
  February, December, May, June, August, ]


Using the new HashMap

The LinkedHashMap essentially works the same way as the LinkedHashSet, but you need a key and a value for each element. It also subclasses from the original class, HashMap in this case, but has five constructors now:

  • LinkedHashMap()
  • LinkedHashMap(int initialCapacity)
  • LinkedHashMap(int initialCapacity, float loadFactor)
  • LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder)
  • LinkedHashMap(Map)

The additional constructor deals with the access order option. Think of a false access order as the default, where you must pass in a true to have the list in access order; that is, the head of the map is the least recently used map entry.

The nice thing about a LinkedHashMap over a regular HashMap is that iteration times are not affected by the map's capacity. Choosing a large capacity does not have any effect on iteration traversal times with a LinkedHashMap, where it does affect performance on a regular HashMap.

Adding elements to the map is a little more involved than adding to a set, only because we have to put() each pair of elements separately. There's nothing special in the following code, just that we're looping through the month names, instead of just passing in a Map to the constructor.

  Map orderedMap = new LinkedHashMap();
  Map unorderedMap = new HashMap();
  for (int i=0, n=months.length; i < n; i++) {
    orderedMap.put(months[i], italianMonths[i]);
    unorderedMap.put(months[i], italianMonths[i]);
  }

Thankfully, like sets, you can just call the toString() method of the map to get the map entries in insertion order. This will return each key-value pair as key=value.

  System.out.println("Ordered:   " + orderedMap);
  System.out.println("Unordered: " + unorderedMap);

The ordered map displays as follows:

Ordered:   {January=gennaio, February=febbraio, March=marzo, April=aprile, 
  May=maggio, June=giugno, July=luglio, August=agosto, September=settembre, 
  October=ottobre, November=novembre, December=dicembre, =}

While the unordered map displays as:

Unordered: {August=agosto, July=luglio, November=novembre, June=giugno, 
  October=ottobre, April=aprile, May=maggio, March=marzo, January=gennaio,
  February=febbraio, =, December=dicembre, September=settembre}

To check for yourself, you can iterate. All the iterators are insertion-order aware, so when you received the values iterator (values()), you can walk through the values in insertion order like this:

  Collection values = orderedMap.values();
  for (Iterator i = values.iterator(); i.hasNext(); 
    System.out.println(i.next()));

to display this:

gennaio
febbraio
marzo
aprile
maggio
giugno
luglio
agosto
settembre
ottobre
novembre
dicembre


Visiting in access order

The last aspect of the new classes we'll examine is the access order option for the LinkedHashMap. Passing true into the LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) constructor allows you to keep the linked list for the map in access order, from least recently used to most recently used. In other words, new items are added to the end, and map lookups move items to the end of the linked list. This last point is important. Because the typical read-access of a map changes the order, if multiple threads could be reading from the map, you should synchronize access.

To demonstrate, we can look up a few months and print the new order:

  Map accessorderedMap = 
    new LinkedHashMap(20, .80f, true);
  for (int i=0, n=months.length; i < n; i++) {
    accessorderedMap.put(months[i], italianMonths[i]);
  }
  accessorderedMap.get("June");
  accessorderedMap.get("April");
  accessorderedMap.get("February");
  System.out.println(accessorderedMap);

Because we accessed three months, they will be moved to the end of the list, with February last and April before June:

{January=gennaio, March=marzo, May=maggio, July=luglio, August=agosto, 
    September=settembre, October=ottobre, November=novembre, 
    December=dicembre, =, June=giugno, April=aprile, February=febbraio}

Note: You'll notice an extra element in the linked map. The = is an extra entry that gets returned by getMethods(). For some reason getMonths() returns 13 months, not 12, where the last one has no name. For the same reason there is a comma with no last element in the linked set example.

Another note: The 1.4 beta 2 version of LinkedHashMap adds a protected removeEldestEntry() method. Subclasses can have this method return true if the oldest node should be removed, for instance to ensure a map doesn't get over n elements.


Complete example

Here's the complete example source.

import java.util.*;
import java.text.*;
public class OrderedAccess {
  public static void main(String args[]) {
    String months[] = 
      new DateFormatSymbols().getMonths();
    String italianMonths[] = 
      new DateFormatSymbols(Locale.ITALIAN).getMonths();
    List list = Arrays.asList(months);
    Set orderedSet = new LinkedHashSet(list);
    Set unorderedSet = new HashSet(list);
    System.out.println("Ordered:   " + orderedSet);
    System.out.println("Unordered: " + unorderedSet);
    Map orderedMap = new LinkedHashMap();
    Map unorderedMap = new HashMap();
    for (int i=0, n=months.length; i < n; i++) {
      orderedMap.put(months[i], italianMonths[i]);
      unorderedMap.put(months[i], italianMonths[i]);
    }
    System.out.println("Ordered:   " + orderedMap);
    System.out.println("Unordered: " + unorderedMap);
    Collection values = orderedMap.values();
    for (Iterator i = values.iterator(); i.hasNext(); 
      System.out.println(i.next()));
    Map accessorderedMap = 
      new LinkedHashMap(20, .80f, true);
    for (int i=0, n=months.length; i < n; i++) {
      accessorderedMap.put(months[i], italianMonths[i]);
    }
    accessorderedMap.get("June");
    accessorderedMap.get("April");
    accessorderedMap.get("February");
    System.out.println(accessorderedMap);
  }
}



Download

NameSizeDownload method
j-mer0821.zip600B HTTP

Information about download methods


Resources

About the author

Author photo

John Zukowski conducts strategic Java consulting with JZ Ventures, Inc. and serves as the resident guru for a number of jGuru's community-driven Java FAQs. His latest books are Java Collections and Definitive Guide to Swing for Java 2 (2nd ed) from Apress. Contact John at jaz@zukowski.net.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

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=10578
ArticleTitle=Magic with Merlin: Maintaining insertion order
publish-date=08012001
author1-email=jaz@zukowski.net
author1-email-cc=jaloi@us.ibm.com

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.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

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).

Special offers