Maps


Yet another alternative to using a switch statement is to use a map. A map is a collection that provides fast insertion and retrieval of values associated with specific keys. An example is an online dictionary that stores a definition (a value) for each word (key) that appears in it.

Java supplies the interface java.util.Map to define the common behavior for all map implementations. For the report card messages, you will use the EnumMap implementation. An EnumMap is a Map with the additional constraint that all keys must be enum objects.

To add a key-value pair to a Map, you use the put method, which takes the key and value as parameters. To retrieve a value stored at a specific key, you use the get method, which takes the key as a parameter and returns the associated value.

Suppose you need to print an appropriate message on a report card for each student, based on their grade. Add a new class named ReportCardTest to the sis.reports package.

 package sis.report; import junit.framework.*; import sis.studentinfo.*; public class ReportCardTest extends TestCase {    public void testMessage() {       ReportCard card = new ReportCard();       assertEquals(ReportCard.A_MESSAGE,                      card.getMessage(Student.Grade.A));       assertEquals(ReportCard.B_MESSAGE,                      card.getMessage(Student.Grade.B));       assertEquals(ReportCard.C_MESSAGE,                      card.getMessage(Student.Grade.C));       assertEquals(ReportCard.D_MESSAGE,                      card.getMessage(Student.Grade.D));       assertEquals(ReportCard.F_MESSAGE,                      card.getMessage(Student.Grade.F));    } } 

Change the Grade enum defined in Student to public to make this code compile.

The ReportCard class:

 package sis.report; import java.util.*; import sis.studentinfo.*; public class ReportCard {    static final String A_MESSAGE = "Excellent";    static final String B_MESSAGE = "Very good";    static final String C_MESSAGE = "Hmmm...";    static final String D_MESSAGE = "You're not trying";    static final String F_MESSAGE = "Loser";    private Map<Student.Grade, String> messages = null;    public String getMessage(Student.Grade grade) {       return getMessages().get(grade);    }    private Map<Student.Grade, String> getMessages() {       if (messages == null)          loadMessages();       return messages;    }    private void loadMessages() {       messages =          new EnumMap<Student.Grade, String>(Student.Grade.class);       messages.put(Student.Grade.A, A_MESSAGE);       messages.put(Student.Grade.B, B_MESSAGE);       messages.put(Student.Grade.C, C_MESSAGE);       messages.put(Student.Grade.D, D_MESSAGE);       messages.put(Student.Grade.F, F_MESSAGE);    } } 

The ReportCard class defines an instance variable messages as a parameterized Map type. The type parameters are Student.Grade for the key and String for the value. When you construct an EnumMap, you must also pass in the class that represents the enum type of its keys.

The getMessages method uses lazy initialization (see the sidebar) to load the appropriate message strings, which you define as static constants, into a new instance of the EnumMap.

Lazy Initialization

You have learned to initialize fields either where you declared them or within a constructor. Another option is to wait until you first need to use a field and then initialize it. This is a technique known as lazy initialization.

Within a getter method, such as getMessages, you first test to see whether or not a field has already been initialized. For a reference instance variable, you test whether or not it is null. If it is null, you do whatever initialization is necessary and assign the new value to the field. Regardless, you return the field as the result of the getter, like you normally would.

The primary use of lazy initialization is to defer the potentially costly operation of loading a field until it is necessary. If the field is never needed, you never expend the cycles required to load it. A minor amount of overhead is required to test the field each time it is accessed. This overhead is negligible for occasional access.

Here, lazy initialization is used as a way of keeping more-complex initialization logic close to the field access logic. Doing so can improve understanding of how the field is initialized and used.


The getMessage method is a single line of code that uses the Map method get to retrieve the appropriate string value for the grade key.

Maps are extremely powerful, fast data structures that you might use frequently in your applications. Refer to Lesson 9 for a detailed discussion of their use.



Agile Java. Crafting Code with Test-Driven Development
Agile Javaв„ў: Crafting Code with Test-Driven Development
ISBN: 0131482394
EAN: 2147483647
Year: 2003
Pages: 391
Authors: Jeff Langr

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net