0% found this document useful (0 votes)
37 views8 pages

Collections: Intermediate Java Programming

The document discusses intermediate Java programming concepts related to collections and data structures in the Java Collections Framework. It covers List, Set, and Map interfaces and some common implementations like ArrayList, HashSet, and HashMap. It provides examples of using collections like ArrayList to store a list of bills, removing elements from a list using an iterator, and issues that can arise with the removeAll() method. The document is an introduction to further concepts in the Java Collections Framework beyond the basic overview provided in prior tutorials.

Uploaded by

simpleraj2006
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
37 views8 pages

Collections: Intermediate Java Programming

The document discusses intermediate Java programming concepts related to collections and data structures in the Java Collections Framework. It covers List, Set, and Map interfaces and some common implementations like ArrayList, HashSet, and HashMap. It provides examples of using collections like ArrayList to store a list of bills, removing elements from a list using an iterator, and issues that can arise with the removeAll() method. The document is an introduction to further concepts in the Java Collections Framework beyond the basic overview provided in prior tutorials.

Uploaded by

simpleraj2006
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 8

Intermediate Java programming https://www6.software.ibm.com/developerworks/education/j-intermed/se...

Intermediate Java programming


Collections
Introduction
The Java Collections Framework is large. In the Introduction to Java programming tutorial, I talked about the
ArrayList class, but that's only scratching the surface. There are many classes and interfaces in the framework.
We'll cover some more, although not all of them, here.

Collection interfaces and classes


The Java Collections Framework is based on concrete implementations of several interfaces that define types of
collections:

The List interface defines a navigable collection of Object elements.


The Set interface defines a collection with no duplicate elements.
The Map interface defines a collection of key-value pairs.
We'll talk about several concrete implementations in this tutorial. This isn't an exhaustive list, but you're likely to see
the following frequently on Java language development projects:
Interface Implementation(s)

List ArrayList, Vector

Set HashSet, TreeSet

Map HashMap

All of the interfaces in the framework except Map are subinterfaces of the Collection interface, which defines the
most general structure of a collection. Each collection consists of elements. As implementors of subinterfaces of
Collection, all collections share some (intuitive) behavior:

Methods that describe the size of the collection (such as size() and isEmpty())
Methods that describe the contents of the collection (such as contains() and containsAll())
Methods that support manipulation of the collection's contents (such as add(), remove(), and clear())
Methods that let you convert a collection to an array (such as toArray())
A method that lets you get an iterator on the array (iterator())
We'll talk about some of these in this section. Along the way, we'll discuss what an iterator is, and how to use it.

Note that Maps are special. They aren't really collections at all. However, they behave very much like collections, so
we'll talk about them in this section as well.

List implementations
Older versions of the JDK contained a class called Vector. It's still there in newer versions, but you should use it
only when you need a synchronized collection -- that is, one that is thread-safe. (Threading is beyond the scope of this
article; we'll briefly discuss the concept in Summary.) In other cases, you should use the ArrayList class. You can
still use Vector, but it imposes some overhead you often don't need.

1 of 8 9/18/2009 11:19 AM
Intermediate Java programming https://www6.software.ibm.com/developerworks/education/j-intermed/se...

An ArrayList is what it sounds like: an ordered list of elements. We already saw how to create one, and how to add
elements to it, in the introductory tutorial. When we created a Wallet nested class in this tutorial, we incorporated an
ArrayList to hold an Adult's bills:
protected class Wallet {
protected ArrayList bills = new ArrayList();

protected void addBill(int aBill) {


bills.add(new Integer(aBill));
}

protected int getMoneyTotal() {


int total = 0;
for (Iterator i = bills.iterator(); i.hasNext(); ) {
Integer wrappedBill = (Integer) i.next();
int bill = wrappedBill.intValue();
total += bill;
}
return total;
}
}

The getMoneyTotal() method uses an iterator to march through the list of bills and total their values. An
Iterator is similar to an Enumeration in older versions of the Java language. When you get an iterator on a
collection (by calling iterator()), that iterator lets you traverse the collection using a couple of important methods,
illustrated in the code above:

hasNext() tells you if there is another element in the collection.


next() gives you that next element.
As we discussed before, you must cast to the correct type when you extract elements from a collection using next().

An Iterator gives us some additional capability, however. We can remove elements from our ArrayList by
calling remove() (or removeAll(), or clear()), but we also can use the Iterator to do that. Let's add a
simplistic method to Adult called spendMoney():
public void spendMoney(int aBill) {
this.wallet.removeBill(aBill);
}

This method calls removeBill() on Wallet:


protected void removeBill(int aBill) {
Iterator iterator = bills.iterator();
while (iterator.hasNext()) {
Integer bill = (Integer) iterator.next();
if (bill.intValue() == aBill)
iterator.remove();
}
}

We get an Iterator on the bills ArrayList, and traverse the list to find a match on the bill value passed in
(aBill). If we find one, we call remove() on the iterator to remove that bill. Simple, but not as simple as it could
be. The following code does the same job and is much easier to read:
protected void removeBill(int aBill) {
bills.remove(new Integer(aBill));
}

You probably won't call remove() on an Iterator very often, but it's nice to have that tool if you need it.

2 of 8 9/18/2009 11:19 AM
Intermediate Java programming https://www6.software.ibm.com/developerworks/education/j-intermed/se...

At the moment, we can remove only a single bill at a time from our Wallet. It would be nicer to use the power of a
List to help us remove multiple bills at once, like this:
public void spendMoney(List bills) {
this.wallet.removeBills(bills);
}

We need to add removeBills() to our wallet to make this work. Let's try this:
protected void removeBills(List billsToRemove) {
this.bills.removeAll(bills);
}

This is the most straightforward implementation we can use. We call removeAll() on our List of bills, passing in
a Collection. That method then removes all the elements from the list that are contained in the Collection. Try
running this code:
List someBills = new ArrayList();
someBills.add(new Integer(1));
someBills.add(new Integer(2));

Adult anAdult = new Adult();


anAdult.acceptMoney(1);
anAdult.acceptMoney(1);
anAdult.acceptMoney(2);

List billsToRemove = new ArrayList();


billsToRemove.add(new Integer(1));
billsToRemove.add(new Integer(2));

anAdult.spendMoney(someBills);
System.out.println(anAdult.wallet.bills);

The results aren't what we want. We end up with no bills in our wallet. Why? Because removeAll() removes all
matches. In other words, any and all matches in our wallet for something in the List we pass to the method are
removed. The bills we passed in contained 1 and 2. Our wallet contains two 1s and a single 2. When removeAll()
looks for matches on the 1 element, it finds two matches and removes them both. That's not what we want! We need to
change our code in removeBills() to account for this:
protected void removeBills(List billsToRemove) {
Iterator iterator = billsToRemove.iterator();
while (iterator.hasNext()) {
this.bills.remove(iterator.next());
}
}

This code removes single matches only, rather than all matches. Remember to be careful with removeAll().

Set implementations
There are two commonly used Set implementations:

HashSet, which does not guarantee the order of iteration.


TreeSet, which does.
The Java language documentation suggests that you'll end up using the first implementation most of the time. In general,

3 of 8 9/18/2009 11:19 AM
Intermediate Java programming https://www6.software.ibm.com/developerworks/education/j-intermed/se...

if you need to make sure the elements in your Set are in a certain order when you traverse it with an iterator, use the
second implementation. Otherwise, the first will do. The ordering of elements in a TreeSet (which, by the way,
implements the SortedSet interface) is called the natural ordering; this means that, most of the time, you should be
able to order the elements based on an equals() comparison.

Suppose that each Adult has a set of nicknames. We really don't care what order they're in, but duplicates wouldn't
make much sense. We could use a HashSet to hold them. First, we add an instance variable:
protected Set nicknames = new HashSet();

Then we add a method to add nicknames to the Set:


public void addNickname(String aNickname) {
nicknames.add(aNickname);
}

Now try running this code:


Adult anAdult = new Adult();
anAdult.addNickname("Bobby");
anAdult.addNickname("Bob");
anAdult.addNickname("Bobby");
System.out.println(anAdult.nicknames);

You'll see only a single occurrence of Bobby in the console.

Map implementations

A Map is a collection of key-value pairs. It cannot contain duplicate keys. Each key must map to a single value, but
that value can be of any type. You can think of a map as a named List. Imagine a List where each element has a
name you can use to extract that element directly. The key can be anything of type Object, as can the value. Once
again, that means you can't store primitives directly in a Map (do you hate primitives yet?). Instead, you have to use the
primitive wrapper classes to store the values.

Although this is a financially risky strategy, we're going to give each Adult a set of admittedly simplistic credit cards.
Each will have a name and a balance (initially 0). First, we add an instance variable:
protected Map creditCards = new HashMap();

Then we add a method to add a credit card to the Map:


public void addCreditCard(String aCardName) {
creditCards.put(aCardName, new Double(0));
}

The interface of the Map is different from the interfaces of other collections. You call put() with a key and a value to
add an entry. You call get() with key to extract a value, which we'll do next in a method that will show us the
balance for a card:
public double getBalanceFor(String cardName) {
Double balance = (Double) creditCards.get(cardName);
return balance.doubleValue();
}

4 of 8 9/18/2009 11:19 AM
Intermediate Java programming https://www6.software.ibm.com/developerworks/education/j-intermed/se...

All that's left is to add the charge() method, which allows us to add to our balance:
public void charge(String cardName, double amount) {
Double balance = (Double) creditCards.get(cardName);
double primitiveBalance = balance.doubleValue();
primitiveBalance += amount;
balance = new Double(primitiveBalance);

creditCards.put(cardName, balance);
}

Now try running this code, which should show you 19.95 in the console:
Adult anAdult = new Adult();
anAdult.addCreditCard("Visa");
anAdult.addCreditCard("MasterCard");

anAdult.charge("Visa", 19.95);
adAdult.showBalanceFor("Visa");

A typical credit card has a name, an account number, a credit limit, and a balance. Each entry in a Map can have only a
single key and a single value. Our simplistic credit cards fit, because they had only a name and a current balance. We
could get more sophisticated by creating a class called CreditCard, with instance variables for all of the
characteristics of a card, then store instances of that class as the values for entries in our Map.

There are some other interesting aspects of the Map interface to cover before we go (this is not an exhaustive list):
Method Behavior

containsKey() Answers whether or not the Map contains the given key.

containsValue() Answers whether or not the Map contains the given value.

keySet() Returns a Set of the keys.

values() Returns a Set of the values.

entrySet() Returns a Set of key-value pairs, defined as instances of Map.Entrys.

remove() Lets you remove the value for a given key.

isEmpty() Answers whether or not the Map is empty (that is, has no keys).

Some of these methods, such as isEmpty() are simply convenient, but some are vital. For example, the only way to
iterate over the elements in a Map is via one of the related sets (of keys, of values, or of key-value pairs).

The Collections class


When you're using the Java Collections Framework, you need to be aware of what's available in the Collections
class. This class contains a host of static methods that support collection manipulation. We won't cover them all here,
because you can read the API yourself, but we'll cover two that show up very frequently in Java code:

copy()

5 of 8 9/18/2009 11:19 AM
Intermediate Java programming https://www6.software.ibm.com/developerworks/education/j-intermed/se...

sort()
The first method lets you copy the contents of one collection to another, like this:
List source = new ArrayList();
source.add("one");
source.add("two");
List target = new ArrayList();
target.add("three");
target.add("four");

Collections.copy(target, source);
System.out.println(target);

This code copies source into target. The target has to be the same size as the source, so you can't copy a List
into an empty List.

The sort() method sorts elements into their natural order. All elements have to implement the Comparable
interface so that they are mutually comparable. Built-in classes like String do already. So, for a set of strings, we
can sort them in lexicographically ascending order with this code:
List strings = new ArrayList();
strings.add("one");
strings.add("two");
strings.add("three");
strings.add("four");

Collections.sort(strings);
System.out.println(strings);

You'll get [four, one, three, two] in the console. But how can you sort classes you create? We can do this
for our Adult. First, we make the class mutually comparable:
public class Adult extends Person implements Comparable {
...
}

Then we override compareTo() to compare two Adult instances. We'll keep the comparison simplistic for our
example, so it's less work:
public int compareTo(Object other) {
final int LESS_THAN = -1;
final int EQUAL = 0;
final int GREATER_THAN = 1;

Adult otherAdult = (Adult) other;


if ( this == otherAdult ) return EQUAL;

int comparison = this.firstname.compareTo(otherAdult.firstname);


if (comparison != EQUAL) return comparison;

comparison = this.lastname.compareTo(otherAdult.lastname);
if (comparison != EQUAL) return comparison;

return EQUAL;
}

Any number less than 0 means "less than," but -1 is a good value to use. Likewise, 1 is convenient for "greater than."
As you can see, 0 means "equal." Comparing two objects in this way is obviously a manual process. You have to
march through the instance variables and compare each. In this case, we compared the first name and last name, and

6 of 8 9/18/2009 11:19 AM
Intermediate Java programming https://www6.software.ibm.com/developerworks/education/j-intermed/se...

effectively sorted by last name. But you should be able to see why our example is simplistic. Each Adult has more
than just a first name and a last name. If we wanted to do a deeper comparison, we would have to compare the
Wallets of each Adult to see if they were equal, which probably means that we would have to implement
compareTo() on Wallet and the rest. Also, to be correct about this, whenever you override compareTo(), you
need to be sure the comparison is consistent with equals(). We don't implement equals(), so we didn't worry
about being consistent with it, but we could have. In fact, I've seen code that includes a line like the following, before
returning EQUAL:
assert this.equals(otherAdult) : "compareTo inconsistent with equals.";

The other approach to comparing objects is to extract the algorithm in compareTo() into a object of type
Comparator, then call Collections.sort() with the collection to be sorted and the Comparator, like this:
public class AdultComparator implements Comparator {

public int compare(Object object1, Object object2) {


final int LESS_THAN = -1;
final int EQUAL = 0;
final int GREATER_THAN = 1;

if ((object1 == null) ;amp;amp (object2 == null))


return EQUAL;
if (object1 == null)
return LESS_THAN;
if (object2 == null)
return GREATER_THAN;

Adult adult1 = (Adult) object1;


Adult adult2 = (Adult) object2;
if (adult1 == adult2)
return EQUAL;

int comparison = adult1.firstname.compareTo(adult2.firstname);


if (comparison != EQUAL)
return comparison;

comparison = adult1.lastname.compareTo(adult2.lastname);
if (comparison != EQUAL)
return comparison;

return EQUAL;
}
}

public class CommunityApplication {

public static void main(String[] args) {


Adult adult1 = new Adult();
adult1.setFirstname("Bob");
adult1.setLastname("Smith");

Adult adult2 = new Adult();


adult2.setFirstname("Al");
adult2.setLastname("Jones");

List adults = new ArrayList();


adults.add(adult1);
adults.add(adult2);

Collections.sort(adults, new AdultComparator());


System.out.println(adults);
}
}

7 of 8 9/18/2009 11:19 AM
Intermediate Java programming https://www6.software.ibm.com/developerworks/education/j-intermed/se...

You should see "Al Jones" and "Bob Smith," in that order, in your console window.

There are some good reasons to use the second approach. The technical ones are beyond the scope of this tutorial.
From the perspective of good OOD, however, it might be a good idea to separate the comparison code into another
object, rather than giving each Adult the ability to compare itself to another. However, since this is really what
equals() does, even though the result is boolean, there are good arguments for either approach.

Using collections
When should you use a particular type of collection? That's a judgment call on your part, and it's because of calls like
this that you hope to be paid very well as a programmer.

Despite what many professionals may believe, there are very few hard and fast rules about which classes to use in any
given situation. In my personal experience, in the vast majority of the times I've used collections, an ArrayList or a
HashMap (remember, a Map isn't a true collection) did the trick. That will probably be the same in your experience.
Here are some rules of thumb, some more obvious than others:

When you think you need a collection, start with a List, then let the code tell you if you need another type.
If you need a unique grouping of things, use a Set.
If the iteration order is important when traversing a collection, use the Tree... flavors of collections, where
available.
Avoid using Vector, unless you need its synchronization capability.
Don't worry about optimization until (and unless) performance becomes an issue.
Collections are one of the most powerful aspects of the Java language. Don't be afraid to use them, but watch out for
the "gotchas." For example, there is a convenient way to convert from an Array to an ArrayList:
Adult adult1 = new Adult();
Adult adult2 = new Adult();
Adult adult3 = new Adult();

List immutableList = Arrays.asList(new Object[] { adult1, adult2, adult3 });


immutableList.add(new Adult());

This code throws an UnsupportedOperationException, because the List returned by Arrays.asList()


is immutable. You cannot add a new element to an immutable List. Keep your eyes open.

8 of 8 9/18/2009 11:19 AM

You might also like