java hosting


JavaRanch Newsletter Articles in this issue :
Storing Objects in Java Part 3 - The Map InterfaceThomas Paul Printable Version
Cindy's Segment - a Whimsical View of the WorldCindy Glass Printable Version
Cattle Drive Update Pauline McNamara Printable Version
Book Review of the MonthCindy Glass
Madhav Lakkapragada
Printable Version
August GiveawaysCarl Trusiak Printable Version
August NewsCarl Trusiak Printable Version

Storing Objects in Java
Part 3 - The Map Interface

by Thomas Paul

In the past two months we discussed the basics of the Collection interface and reviewed the children of this interface, the List and Set interfaces. This month we will look at the Map interface. What exactly is a Map in Java? A Map is simply a class that stores key-value pairs and provides a way to locate a value based on the key. An array is simply a list of objects that allows you to find an object by specifying a number. A Map allows you to specify an Object to find a different Object. Imagine a Map containing Employee objects for eaach employee in your company. A Map would allow you to locate a particular Employee object in the Map by specifying a key such as their Social Security Number. A Map can not contain a duplicate key.

The Map interface is a replacement for the Dictionary class which is now considered obsolete. There are seven non-abstract implementations of the Map interface that we will discuss. The Hashtable and Properties classes have been around since JDK 1.0. TreeMap, HashMap, and WeakHashMap were added in JDK 1.2. Two new classes were added in J2SE 1.4. These are the LinkedHashMap and the IdentityHashMap. Each implementation contains features that make it appropriate for particular applications. Each of the classes has a unique feature that makes its use desirable in certain circumstances. The HashMap is the basic Map implementation. Hashtable is synchronized. TreeMap maintains keys in a sorted order. LinkedhashMap maintains the objects in the order they were added to the Map. The IdentityHashMap is a special Map that maintains key by reference equality (they point to the same object) rather than object equality (they contain the same value). WeakHashMap is a Map with weak keys, that is, objects in a WeakHashMap will be garbage collected if the only reference to them is the WeakHashMap itself. Finally, the Properties class is a special class used to access and maintain properties files that contain name value pairs.

Overall performance is best with the HashMap. The Hashtable is synchronized so performance is slightly worse. The performance of the Properties class is almost identitcal to the HashTable. TreeMap is slower because it maintains keys in a sorted order.

Testing of Map objects.

Type

Test size

Put

Get

Iteration

TreeMap

10

26.5

15.6

56.3

 

100

31.7

18.9

35.16

 

1000

26.9

21.7

7.0

HashMap

10

14.0

11.0

28.1

 

100

12.2

12.6

38.9

 

1000

9.2

12.3

7.0

Hashtable

10

15.6

12.5

51.6

 

100

20.2

14.7

49.8

 

1000

12.1

18.8

9.6

IdentityHashMap

10

18.8

25.0

35.9

 

100

22.2

25.3

32.6

 

1000

18.8

25.2

6.3

LinkedHashMap

10

20.3

10.9

23.5

 

100

18.9

11.6

17.7

 

1000

14.5

12.0

3.3

Figure 1: relationships between the classes and interfaces of the Map interface

The Map interface

The map interface contains one static nested interface, Map.Entry which we will discuss in a moment. The Map contains the basic methods for all Map implementations such as put and get. In addition, the Map provides three separate ways to get objects from it as Collection objects. You can get a Set of keys, a Collection of values, or a Set of key-value pairs stored in a Map.Entry object.

Here are some of the key methods of the Map interface:

  • Object put(Object key, Object value) - Stores the value and the key into the Map. If the Map already had the specified key, then the value parameter will replace the previous value and the previous value will be returned. If no matching key is found then null is returned.
  • Object get(Object key) - Returns the value found in the Map using the specified key.
  • boolean containsKey(Object key) - Returns true if the key is found in the Map.
  • boolean containsValue(Object value) - Returns true if the value is found at least once in the Map.
  • void clear() - Removes all entries from the Map.
  • Object remove(Object key) - Returns the value for the specified key and removes the key-value pair from the Map.
  • int size() - Returns the number of key-value pairs in the Map.
  • boolean isEmpty() - Returns true if the Map contains no entries.
  • Collection values() - Returns a Collection object containing all the values found in the Map. The Collection is actually backed by the Map so changes should not be made to the Map while iterating through the Collection. Although you can remove items from the Collection (and the underlying Map) using the remove methods of the Collection and iterator, the add methods are not supported..
  • Set keySet() - Returns a Set object containing all the keys found in the Map. The same rules apply for this Set as applied to the Collection returned by the values( ) method.
  • Set entrySet() - Returns a Set object containing all the key-value pairs found in the Map as Map.Entry objects. The same rules apply for this Set as applied to the Collection returned by the values( ) method.

The Map.Entry Interface

The Map interface contains a static nested interface called Entry. This interface is used to access key-value pairs as individual objects outside of the Map. The entrySet( ) method can be used to get individual key-value pairs out of the Map. You can then use methods of the Map.Entry interface to get the key or valu out of the Object.

Here are some of the key methods of the Map.Entry interface:

  • Object getKey() - Returns the key portion of this Entry.
  • Object getValue() - Returns the value portion of this Entry.
  • Object setValue(Object value) - Replaces the value portion of this Entry with the parameter. The replaced value is returned.


The HashMap class

The HashMap class is the simplest implementation of the Map interface. The HashMap does not add any additional methods (other than clone) beyond those found in the Map interface. The HashMap achieves good performance by using a hash to store the key in the Map. The hash allows fast lookup which means that the containKey( ) method will perform much better than the containsValue( ) method. Any Object used as a key in a HashMap must implement the hashCode( ) and equals( ) methods. See Part 2 of this series for a discussion of this issue.

The HashMap does not guarantee the order of the items in the Map and allows one null key. Duplicates are not permitted. The HashSet offers "constant time" performance for lookups involving the key and linear time for lookups based on value. This means that adding items to the Map will not cause significant performance degradation as long as lookups are done by the key. The performance of basic functions such as put, remove, get, etc is based on two factors which can be specified in the constructor of the HashMap, initial capacity and load factor. See the HashSet discussion in Part 2 of this series for the further discussion of these parameters.

The LinkedHashMap Class

New to J2SE 1.4, the LinkedHashMap class is used in exactly the same way as the HashMap class. It has no additional methods but it does have one additional constructor that we will discuss in a moment. The basic difference between HashMap and LinkedHashMap is that the LinkedHashMap maintains the order of the items added to the Map. It does this by maintaining a doubly linked list containing the hash and the original order of the items. According to Sun, the LinkedHashMap should run nearly as fast as the HashMap.

The LinkedHashMap has one additional constructor that takes an additional boolean parameter. This allows you to construct a LinkedHashMap that maintains items, not in the order that they are added to the Map but rather in the order in which they are accessed.

The Hashtable Class

Part of Java since JDK 1.0, the Hashtable class is a synchronized implementation of the Map interface. It has three methods that are not part of the Map interface (contains, keys, and elements) that should be avoided since the Map interface has methods (containsValue, containsKey, and values) that provide the identical functionality. The main difference between HashMap and hashtable is that the hashtable is synchronized, hoewever, synchronization can be achieved by using the Collections.synchronizedMap method on the HashMap. The Hashtable does not permit null keys or null values. The Hashtable should be treated as a class left in java to support maintenance of older programs.

The WeakHashMap Class

The WeakHashMap is virtually identical to the HashMap. The difference is that entries in this class do not count as a reference against the key contained in this Map. This means that over time, the garbage collector may remove keys from the WeakHashMap and garbage collect the object. This would give the appearance that objects are being removed from the Map. The size( ) method may return different values over time. The isEmpty( ) method may return false and then true. Value objects in the WeakHashMap will be garbage collected only if their key is removed and they have no other reference to them. It should be noted that if the value object has a reference to its own key object, the key objetc will not be garbage collected. This situation should be avoided.

The IdenitityHashMap Class

The IdentityHashMap is also like the HashMap with the exception that a key is considered equal to another key only if they are pointing to the exact same object. Other implementations of Map use the equals( ) method to determine if two keys are equal. The IdentityHashMap uses the == comparator. Two keys (a and b) are considered equal if a == b. The IdentityhashMap should only be used in the cases where this functionality is required. It should not be used otherwise.

The TreeMap class

The TreeMap class guarantees that the keys in the Map will be sorted in ascending order by either the keys natural order or by a Comparator provided to the constructor of the TreeMap. Searching for an item in a TreeMap will be slower than in a HashMap because the hashing algorithm gives better performance than the compareTo() method which is used to locate items in a TreeMap. In part 2 of this series, we discussed how to control the sorting of the TreeSet. The same methods apply to controlling the sorting of the TreeMap.

TreeMap does add several new methods to the Map interface.

  • Object firstKey() - Gets the first key from the sorted Map.
  • Object lastKey() - Gets the last key from the sorted map.
  • SortedMap headMap(Object toKey) - Returns a view of the portion of this Map whose keys are less than toKey.
  • SortedMap tailMap(Object fromKey) - Returns a view of the portion of this Map whose keys are greater than or equal to fromKey.
  • SortedMap subMap(Object fromKey, Object toKey) - Returns a view of the portion of this Map whose starting key is greater than or equal to fromKey and whose ending key is less than toKey.

The Properties class

The Properties class is very simialr to the Hashtable and has been part of Java since JDK 1.0. The Properties class adds additional functionality that can be extremely useful. The Properties class represents a persistent list of properties. What exactly does this mean? The Properties class is designed to provide methods to store and load files containing key-value pairs as Strings. Properties files are simply key-value pairs where the key and value are separated by an "=" (name=Tom) and eack key-value pair is on a separate line. A Windows ini file is an example of a properties file. In many cases, XML files are replacing properties files but the simplicity of a properties file combined with its ease of use makes the Properties class still a very useful class.

Although the Properties file inherits the methods of the Hashtable, it is recommended that the Hashtable put method not be used as this may allow the insertion of non-String objects. Only Strings should be used as either a key or a value in a Properties object. A Properties object with a non-String in it will throw an exception if you attempt to store it to a file. A Properties object can contain another Properties object (specified in the constructor) which is used as the default keys if no matching key is found in the Properties object.

The Properties class provides several new methods:

  • Object setProperty(String key, String value) - Invokes the Hashtable put method. Although it returns an Object, the return should always be a String.
  • String getProperty(String key) - Returns the value found for the matching key. Null if no match is found.
  • String getProperty(String key, String defaultValue) - Returns the value found for the matching key.The defaultValue is returned if no match is found.
  • void list(PrintStream output) - Writes the Properties object out to the specified PrintStream.
  • void list(PrintWriter output) - Writes the Properties object out to the specified PrintWriter.
  • void load(InputStream input) - Loads data into the Properties object using the specified InputStream.Key-value pairs are assumed to be on separate lines and each kei is separated from its value by an equals sign ("="). In addition to the equals sign, a colon (":") or the first white space will be used as a separator when reading in a properties file.
  • void store(OutputStream output, String header) - Writes the Properties object out to the specified OutputStream. The header is written as a comment line at the beginning of the file. After the header line, another comment line is written containing the current date and time. A "#" is placed at the beginning of these lines to identify them as comments. The OutputStream will be flushed but will remain open. Any properties in the default Properties object are not written to the output.

Using the Properties class

Here is an example of reading in a properties file, removing the password and printing out the reaminder. As you can see, using the Properties class is very simple.

import java.util.*;
import java.io.*;

public class PropsDemo {

    public static void main(String[] args) throws Exception {

        BufferedInputStream bStream = new BufferedInputStream(new FileInputStream("prefs.ini"));
        Properties props = new Properties();
        props.load(bStream);
        props.remove("password");
        props.list(System.out);
        bStream.close();
    }
} 

Conclusion

We have taken a quick look at the main implementations of the Map interface and also examined how we can make use of properties files. As we have seen, there are quite a few Map objects and which Map object you wish to use will depend greatly upon how you intend on using it in your application. Like the Set interface, performance is less a concern in choosing among Map objects. The main concern is the functionality you require.

Next month we will wrap up this series and take a look at the many additional functions found in the Collections class.


Return to Top

Cindy's Segment - a Whimsical View of the World

Segment 6:
Maintaining your Structural Integrity
Or -
Corned Beef Hash. . . .Codes


You know those quizzes in magazines that you can take to determine your personality? Don?t you just LOVE them! At any rate, I thought that it would be fun to find out about the personality, stability and integrity of various classes.

Now just close your eyes and imagine that you ARE your favorite class. Then answer each of the questions below, and find out just how classy you really are.

Object Oriented Personality Quiz

Pick the answer that best describes your personality:

I. In your class, when comparing yourself to others: (select one)

1. You do not override the equals() method of Object.

2. You do not believe that your equals() method would ever be invoked even if you had one.

3. You do not override the equals() method, but one of your super classes HAS.

4. You have an equals() method of your own.

Analysis:- If you selected:

1. You believe yourself to be unique and unequaled. The only thing that you will say that you are equal to is yourself. If you happen to be a dynamic personality, such as a Thread, rather than a stable personality with a value, this MAY be true. On the other hand, you may just not CARE whether anybody has a clue who you are equal to and you are perfectly happy letting everyone think that you are only equal to yourself. Quite an egotistic attitude.

2. You are a very private sort, and do not go out much. You believe yourself to be invisible to anyone that would ever possibly use the equals() method. You need to get a grip on yourself and work on self-confidence. Get out there and GET an equals() method - it is the right thing to do.

3. You are content to be judged based on the rules laid out by your ancestors. You are confident that whatever they said is good enough for you. Basically, you are afraid to strike out on your own and define your own personality. You are a wimp.

4. You are a personality in your own right. You are attempting to be a mature, well rounded class and live up to your responsibilities.


Now check out the next question to find out how well you are doing with your equals() method.

II. When invoking your equals() method on an instance of your class: (answer each one true or false)

1. When comparing the instance to itself, your equals() method always returns ?true?.

2. When comparing the instance to a second instance of your class, you always get the same result as if the second instance compares itself to the original.

3. When comparing the instance to a second instance many times, you always get the same answer (presuming that the instances are not modified).

4. When you compare the instance to ?null? your equals() method always returns ?false?.

5. When you say that instance 1 is equal to instance 2 and instance 2 is equal to instance 3, then it is always true that instance 1 is equal to instance 3.

6. You answered false to any of the above.

Analysis:- If you answered true:

1. Your reflexive instincts are good, which means that you have a solid sense of self identity.

2. You are fair and symmetric. You are not influenced by who is asking the question.

3. You are consistent and stable. You can be relied on and trusted. You are really cool.

4. You can recognize thin air on your own. This is a basic survival requirement.

5. You are capable of the higher level of consciousness known as transitiveness.

6. You have a problem. Get help immediately.


III. When you overrode the equals() method: (answer each one true or false)

1. You made sure to leave the argument of the equals(Object o) method as Object.

2. You always use the instanceof operator to check if the incoming argument is the correct type.

3. You start out with a check to see if you are comparing the instance to itself by using a == check.

4. Your method checks each field of the class one by one, comparing the contents of both objects to insure that each field is equal.

5. You have identified any unreliable sources that might change without you knowing it and omitted them from the comparison.

6. You overrode the hashCode() method also.

7. You answered false to any of the above.

Analysis:- If you answered true:

1. Of course the only thing coming in should always be ?MyType? but you have resisted the urge to state that in the signature, and therefore you have avoided accidentally overloading equals(Object o) instead of overriding it. You have shown exceptional willpower. Good Job!

2. Well, you left the door open for this above, so you just have to deal with it. And yes - this is a bit of an elitist attitude, but the facts of life say that you just can NEVER be the same as any other type than you ARE, so trying to compare yourself to others is a bad idea.

3. You are not easily hoodwinked. You check for obvious set-ups before putting any effort into comparisons.

4. You are methodical and complete. You do not let complexity overwhelm you.

5. You recognize flighty characteristics in yourself and do not use those aspects of your personality in defining yourself. Of course this means that your instance might be considered equal to some instance that has a different value in that field, but you have acknowledged that, come to terms with it and moved on.

6. You recognize that when defining your equals() method, you are defining what makes you unique, and that eventually someone is going to want to put some order to your instances, and they will without a doubt use the hashCode() method to do that. In fact since all the HashMap, HashSet, etc. classes count on this method working hand in hand with equals, you KNOW that this is important.

7. Once again, you have a problem. Get help immediately. Professional help.


IV. When you overrode the hashCode() method: (answer each one true or false)

1. You didn?t, even though you overrode the equals() method.

2. Your hashCode() method always returns the same value for every instance.

3. Your hashCode() method returns the same value for several instances that are NOT equal.

4. Your hashCode() method always returns the same value for the same instance over and over unless you start your application over, then it consistently returns a different value.

5. Your hashCode() method returns different values for different instances even if they are considered equal using your equals() method.

6. Your hashCode() method skips some fields in your object state because that way the hashCode() method runs faster.

7. Your hashCode() method returns something other than an int value.

Analysis:- If you answered true:

1. You fool! The hashCode() method MUST return the same result for all instances that are equal. When you changed the definition of what makes instances equal, you have to let hashCode() in on the secret or nothing will work as expected. You can plan on spending much of your life in confusion.

2. You try to get away with whatever you can. You feel that because this will compile and run, that you have done your duty. Even if it runs REALLY POORLY, which this will.

3. You play by the rules. Exactly. And that is fine. However, you are NOT expecting optimal performance, which is good, because you will probably not get it if there are too many instances that get identical results.

4. You are not chained by the opinions of others. You know that this is valid EVEN IF it bothers others, and you stand your ground.

5. You have no internal integrity. You are confused and mixed up and will spread that condition to all who interact with you.

6. You are easily confused and do not recognize the difference between immediate savings and long term benefits. You will spend much of your life waiting for hash-based activities to complete because they could be extremely slow. Learn to appreciate boredom.

7. Careful, the compiler will get you.


V. When you overrode the equals() method: (Select one)

1. You also overrode the toString() method, however the output String sort of reads like a core dump. You did not implement the Comparable interface.

2. You also overrode the toString() method trying to make the output String as readable as possible. You did not implement the Comparable interface.

3. You also overrode the toString() method trying to make the output String as readable as possible. You also implemented the Comparable interface.

4. You also overrode the toString() method trying to make the output String as readable as possible and as inclusive of all of the fields as possible. You also implemented the Comparable interface and did it well.

Analysis:- If you selected:

1. You are a techno-weenie at heart and should not be allowed to participate in design decisions. All of your code should be reviewed by persons resembling humans before being released for public consumption.

2. You are competent, but do not go the extra mile. Adequate is good enough for you.

3. You try to excel at everything, and often succeed. If you did a good job at implementing the Comparable contract then you should be proud of yourself.

4. So you are James Gosling!! Well, maybe Joshua Bloch. I knew that JavaRanch would rope you guys in sooner or later. Can we see the code????

Copyright ? 2002. Cindy Glass. All rights reserved.


Graphics by Pauline McNamara and Stephanie Grasson

Next month - "Asserting Yourself in Public"- or - "Testing your Skills"

?

?


Return to Top
Movin' them doggies on the Cattle Drive

It's where you come to learn Java, and just like the cattle drivers of the old west, you're expected to pull your weight along the way.

The Cattle Drive forum is where the drivers get together to complain, uh rather, discuss their assignments and encourage each other. Thanks to the enthusiastic initiative of Johannes de Jong, you can keep track of your progress on the drive with the Assignment Log. If you're tough enough to get through the nitpicking, you'll start collecting mooses at the Cattle Drive Hall of Fame.

Gettin' them doggies...
This month the number of Cattle Drivers wrastlin' Java code has stayed around 20. The Servlets corral has the most ropin' going on, followed closely by the activity in the Java Basics corral. More than half of the drivers on the assignment log are busy with OOP, Servlets and JDBC.

Fresh riders on the Drive...
A big welcome to the new riders on the log: Bryant Constant, Jeremy Thorton, JD Lambert and Brian Coates. Check yer spurs folks, you'll be needin' em!

Another moose on the wall for...
Yep, that's right, you make it through, you get yerself a nice little moose to hang on the wall. Well, OK, so it's a virtual moose on a virtual wall, but you can be right proud of 'em! Thanks to the efforts of Marilyn deQueiroz, you can now proudly admire your codin' accomplishments at the recently opened Cattle Drive Hall of Fame. Check it out, pardner, it's worth a wink.

This month Gerald Dettler showed lots of persistence and bagged a moose on the OOP trail of the drive. Way to go Gerald! Congrats also to Louise Haydu, who picked up a Servlets moose, no easy task!

Saddle sore...
So close and yet so far, that's how it feels when you're just about to get through one of the Cattle Drive sections. Two consistent riders, Manju Jain and Louise Haydu, are both just about done with those Servlets assignments. Hang in there, cowpokes, yer almost there!

Changin' hands at the reins...
You'll notice another new moderator at the Cattle Drive forum: Dirk Schreckmann, the fastest Cattle Driver in the west, is stepping in to help out with all those wild riders, while Pauline McNamara eases up on her Cattle Drive chores. Big thanks Dirk!

Nitpicking is hard work too...
We know they're workin' reeeeeally hard, after all, we've seen what those assignments look like once the nitpickers have combed through 'em. Hats off to Marilyn deQueiroz and Jason Adam for their dedication and patience with the pesky vermin that always manage to make their way into those assignments. Newbie nitpicker Pauline McNamara has started collecting nits too.

Tips for the Trail...
Ever get one of those nitpicks about optimization? Yer not alone pardner. So here's a couple sources of inspiration for yer tough optimization decisions: check out this thread over at the CD forum. Happy codin'!

Written by Pauline McNamara


Return to Top
Book Review of the Month

SCWCD Exam Study Kit
by Hanumant Deshmukh and Jigneh Malavia
The book is laid out in a logical straightforward fashion -- matching up exam objectives with Servlet/JSP topics and even covers a couple things that aren't (yet) on the exam, like Filters. It's written in a very easy-to-read, conversational tone and is an excellent resource for someone who's familiar with Java but not with Servlets and JSPs or even for someone familiar with them, but needs to brush up on some of the details for the exam.

The bundled CD that comes with the book is chock full of excellent resources (3 JwebPlus mock exams, Tomcat 4, the relevant JSP and Servlet specs, and an electronic copy of the book). The quizlets and notes intermixed within each chapter help you to confirm that you understood what you just read -- and also explain a couple ?gotchas?.

The author's website contains a excellent little forum where you can get hold of the author's to ask questions or report errors in the book. I'll definitely use this book as a resource even after the exam. (Jessica Sant - Bartender, July 2002)


More info at Amazon.com || More info at Amazon.co.uk

Chosen by Cindy Glass and Madhav Lakkapragada

Return to Top
August Giveaways

Starting Date Book Author(s) Publisher JavaRanch Forum
Aug 6 Java Development with Ant Erik Hatcher
Steve Loughran
Manning Publications Co. Jakarta Projects
Aug 13 Learn Java with JBuilder 6 John Zukowski APress IDE's and other tools
Aug 20 JSTL in Action Shawn Bayern Manning Publications Co. JSP
Aug 27 JSP Examples and Best Practices Andrew Patzer APress JSP

For more information on JavaRanch's Giveaways see Book Promotion Page.

Return to Top
August News

Hey, we've added a Tack Room. No one should be out on the range without their vital JavaRanch supplies. T-shirts, caps, lunch bags, and mugs will keep you ready whether you are out on a cattle drive or just dropping in to the saloon.

As always JavaRanch is dedicated to providing you with the best source of information on Java Programming and Engineering.

by Carl Trusiak


Return to Top

Managing Editor: Carl Trusiak

Comments or suggestions for JavaRanch's NewsLetter can be sent to the NewsLetter Staff
For advertising opportunities contact NewsLetter Advertising Staff