Using Maps

advertisement
Using Maps
A simple map: Hashtable

To create a Hashtable, use:
import java.util.*;
Hashtable table = new Hashtable();

To put things into a Hashtable, use:
table.put(key, value);

To retrieve a value from a Hashtable, use:
value = table.get(key);
2
Example use of a Hashtable
import java.util.*;
public class HashtableUser {
public static void main(String[] args) {
Hashtable<String, String> table =
new Hashtable<String,
String>();
table.put("one", "un");
table.put("two", "deux");
table.put("three", "trois");
System.out.println("two -> " + table.get("two"));
System.out.println("deux -> " + table.get("deux"));
}
}
two -> deux
deux -> null
3
Hashtable constructors


Hashtable()
 Constructs a new, empty Hashtable with a default capacity
(11) and default load factor (0.75).
Hashtable(int initialCapacity)
 Constructs a new, empty Hashtable with the specified initial
capacity and the default load factor (0.75).

Hashtable(int initialCapacity, float loadFactor)
 Constructs a new, empty Hashtable with the specified initial
capacity and the specified load factor.

Hashtable(Map t)
 Constructs a new Hashtable with the same mappings as the
given Map.
4
Which constructor should you use?

This is basically a question of efficiency




A hash table that is mostly empty wastes space
If a hash table is nearly full, some searches may take a
very long time
The initial capacity of a hash table is the number
of entries that it can hold initially
The load factor is a measure of how full it is



A load factor of 75% is usually a good compromise
If the table gets fuller than the load factor, Java creates
a new, larger hash table and rehashes everything
Rehashing is an expensive operation
5
Hashtable constructors (again)

Hashtable()
 Use if the default values are good enough

Hashtable(int initialCapacity)
 Use if you have some idea how many entries to expect
 Try to ensure it won’t be more than 75% full
 If space is not an issue, double or triple the size

Hashtable(int initialCapacity, float loadFactor)
 Use if you are trying to be super efficient
 Requires careful experimentation and tuning

Hashtable(Map<? extends K, ? extends V> t)
 Use to make a Hashtable from some other map
 Initial capacity = 2*(size of t), load factor = 0.75
6
The Collections framework
Collection
Set
Map
List
SortedMap
Hashtable
SortedSet

Hashtable is an old (pre-Collections) class

Hashtable has been retrofitted to implement the Map
interface
7
The Map interface I

Basic operations:



V put(K key, V value)
 Returns the previous value associated with key, or null if
there was no previous value
V get(Object key)
 Returns null if the key was not found
 A return value of null may not mean the key was not found
(some implementations of Map allow null keys and values)
Tests:




boolean containsKey(Object key)
boolean containsValue(Object value)
 Warning: probably requires linear time!
boolean isEmpty()
boolean equals(Object o)
 Returns true if o is also a map and has the same mappings
8
The Map interface II

Optional operations:





V put(K key, V value)
 (So you could implement an immutable map)
void putAll(Map t)
 Adds the mappings from t to this map
void clear()
Object remove(Object key)
 Returns the value that was associated with the key, or null
Other:


int size()
 Returns the number of key-value mappings
int hashCode()
 Returns a hash code value for this map
9
Optional operations


Question: How can a method declared in an
interface be optional?
Answer: you have to implement it, but the
implementation may be something like this:
public void remove(Object key)
throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}

In fact, HashMap extends AbstractMap, which
provides many of the map operations, and
implements the optional operations exactly this way
10
Map views

Set<K> keySet()


Collection<V> values()



Returns a set view of the mappings contained in this map.
A view is dynamic access into the Map



Returns a collection view of the values contained in this map
Can’t be a set—keys must be unique, but values may be repeated
Set<Map.Entry<K, V>> entrySet()


Returns a set view of the keys contained in this map.
If you change the Map, the view changes
If you change the view, the Map changes
The Map interface does not provide any Iterators

However, there are iterators for the above Sets and Collections
11
Map.Entry:
Interface for entrySet elements

public interface Entry {
K getKey();
V getValue();
V setValue(V value);
}

This is a small interface for working with the
Collection returned by entrySet()
Can get elements only from the Iterator, and
they are only valid during the iteration

12
Constructors

Map is an interface, so it cannot require any constructors

However, Java always supplies:



A no-argument constructor for each Map type
A constructor that takes a Map argument, and copies its keyvalue pairs into the new Map
If you ever implement your own Map class, you should
define these constructors

Defining your own Map class is easy:
class MyMap implements Map { ... }

There are, however, a lot of methods to implement
13
Hazards I

In order for a Hashtable to work correctly,

equals must be defined properly on the keys

hashCode must be defined properly on the keys

This is not a problem if you use Strings for the keys (this is
extremely common)

If you use objects of some other class as your keys, you must
make sure equals and hashCode are properly defined

Note: equals and hashCode are properly defined for all of
Java’s Maps; it’s the keys that you need to be careful with
14
Hazards II

You should use immutable objects (like Strings) as
keys

If you put a value into a hash table with a mutable key,
and you change the key, what happens?

Answer: Nothing good!

Special case #1: A map may not contain itself as a key

Special case #2: A map may contain itself as a value,
but equals and hashCode are no longer well-defined

These special cases are really weird and you will
probably never get anywhere near them
15
From Hashtables to HashMaps

Hashtable has been around a long time, but HashMap is

new with Java 1.2
So why am I teaching you the old stuff?



Actually, except for the constructors, I’ve been talking about
the Map interface, which both Hashtable and HashMap
implement
Both are cloneable (more on this later) and serializable
Differences:

Hashtable is synchronized; HashMap is not

HashMap permits null values and (one) null key; Hashtable
does not
16
synchronized

Java supports multiple Threads





A Thread is an execution sequence
Having multiple Threads means that Java appears to be
doing many different things all at the same time
Threads can interfere with each other unless they are
carefully synchronized (prevented from both using the
same data at the same time)
This can be an issue with GUIs, which run in a different
Thread from the rest of the program
If you use a hash table from an event handler, use a
Hashtable (which is synchronized) instead of a HashMap
(which is not)
17
Copying objects
• In Java, you seldom copy objects, you just copy
references to objects
Person mary = new Person("Mary", 21);
Person john = new Person("John", 23, mary);
mary.setSpouse(john);
Person jack = john;
jack.name = "Jack";


john
jack
"Jack"
"John"
23
"Mary"
"John"
21
Suppose, however, that you really do want to make a copy;
how do you do it?
Answer: you clone the object
18
The Cloneable interface

Cloneable, like Serializable, is a marker interface: it doesn't require

any methods
It does, however, allow you to use the clone method

class Person implements Cloneable { ... }

...
Person jack = john.clone();
clone() makes a shallow copy


If you want a deep
john
copy, you have to
jack
write a lot more code
Avoid making copies
if possible; it’s not
easy and it’s expensive
"John"
23
"Mary"
"John"
21
"John"
23
19
Copy constructors





Rather than use cloneable, it’s usually better to write a copy
constructor—a constructor that takes an object as a parameter and
makes another object just like it
Example: Person jack = new Person(john);
There is nothing magic about a copy constructor—it’s up to you
to make a deep copy rather than a shallow copy
Person (Person original) {
this.name = original.name;
this.spouse = new Person(original.spouse);
this.spouse.spouse = this; // why?
}
Does this actually work?
20
The SortedMap interface

A hash table keeps elements in an (apparently)
random order

Sometimes you want the keys of a map to be in
sorted order (e.g. phone book, dictionary)

A map can be implemented with a hash table, but
it doesn’t have to be

The SortedMap interface implements the Map
interface and provides additional methods

For efficiency, you want an implementation that
keeps its elements in some kind of order
21
Requirements for SortedMap

A SortedMap keeps its elements in the order of increasing
key values

Therefore, it must be possible to sort the keys!

This means:




The keys must be objects of a type that implement the Comparable
interface (or be given a Comparator)
Keys must be mutually comparable (e.g. you can’t compare a
String to a Button)
The ordering must be consistent with equals
All implementations of SortedMap should supply four
constructors

We’ll see an example of these shortly
22
SortedMap Methods I

Comparator<? super K> comparator()





K firstKey()


Returns the comparator associated with this sorted map, or
null if it uses its keys' natural ordering.
<?> means any type
<? extends T> means type T or any subtype of T
<? super T> means type T or any supertype of T
Returns the first (lowest) key currently in this sorted map.
K lastKey()

Returns the last (highest) key currently in this sorted map.
23
SortedMap Methods II

SortedMap<K, V> headMap(K toKey)


SortedMap<K, V> subMap(K fromKey,
K toKey)


Returns a view of the portion of this sorted map whose keys
are strictly less than toKey.
Returns a view of the portion of this sorted map whose keys
range from fromKey, inclusive, to toKey, exclusive.
SortedMap<K, V> tailMap(K fromKey)

Returns a view of the portion of this sorted map whose keys
are greater than or equal to fromKey.
24
The TreeMap class

TreeMap implements SortedMap

TreeMap is the only implementation that Java provides
for SortedMap


Question: Since there’s only one implementation, why
bother to have a separate interface?
Answer: To give you the flexibility to define additional
kinds of sorted map, if you wish to

You probably won’t—but the flexibility is there
25
TreeMap constructors

TreeMap()


TreeMap(Comparator<? super K> c)


Constructs a new, empty map, sorted according to the given comparator.
TreeMap(Map<? extends K, ? extends V> m)


Constructs a new, empty map, sorted according to the keys' natural order.
Constructs a new map containing the same mappings as the given map,
sorted according to the keys' natural order.
TreeMap(SortedMap<K, ? extends V> m)

Constructs a new map containing the same mappings as the given
SortedMap, sorted according to the same ordering.
26
Quick summary

Interfaces (cannot instantiate):





Classes (can instantiate):




Hashtable
HashMap
TreeMap
As always, it’s best to avoid exposing the implementation; hence:


Map
SortedMap
Serializable
Cloneable
Map<String, String> myMap = new HashMap<String, String>();
But probably not:

Map<String, String> myMap = new TreeMap<String, String>();
27
Sets

We’ve talked about Sets before, and you probably
remember the basic operations:



int size( );
boolean isEmpty( );
boolean contains(Object e);
boolean add(E e);
boolean remove(Object e);
Iterator<E> iterator( );
However, Set is an interface, not a class
There are two supplied implementations: HashSet
(for when you don’t care about the order of
elements) and TreeSet (for when you do)
28
The End
29
Download