slanted W3C logo

Day 23 — Collections 2

A collection is an object that groups multiple object references into a single unit. You can think of a collection as representing a container for objects where each object is usually referred to as an element.

Adding Elements

Most collections support adding elements to the collection through a method named add. Some collections place limitations on what elements may be added. Adding an element might fail if:

Failure to add an element is either indicated by the add method returning false or throwing an exception.

Adding to a Portfolio

Recall that a Portfolio is a statically allocated collection (has a fixed capacity).

A Portfolio lets a client add investments to it until it is full (reached its capacity); otherwise, there are no restrictions on the investments that may be added.

Consider a Portfolio with capacity 3:

Adding to a Portfolio

Portfolio pf = new Portfolio("Small Portfolio", 3);

Stock stockA = new Stock("HR.A");
Stock stockB = new Stock("HR.B");
Stock stockC = new Stock("HR.C");
Stock stockD = new Stock("HR.D");

output.print(pf.add(new Investment(stockA, 1, 1.00)));
output.println(" " + pf.size());

output.print(pf.add(new Investment(stockB, 1, 2.00)));
output.println(" " + pf.size());

output.print(pf.add(new Investment(stockC, 1, 3.00)));
output.println(" " + pf.size());

output.print(pf.add(new Investment(stockD, 1, 4.00)));
output.println(" " + pf.size());

The above code fragment prints:

true 1
true 2
true 3
false 3

Adding to a GlobalCredit Collection

Recall that GlobalCredit is a dynamically allocated collection (has no fixed capacity); thus, its add method will not fail because of capacity.

A GlobalCredit collection will only allow unique credit cards to be added (it prevents duplicate credit cards from being in the collection); otherwise there are no restrictions on the credit cards that may be added. If a client tries to insert a credit card that is already in the collection, the add method returns false and the credit card is not added.

Two CreditCard instances are considered duplicates if equals returns true.

Adding to a GlobalCredit Collection

GlobalCredit cards = new GlobalCredit();

CreditCard cardA = new CreditCard(111111, "John A");
CreditCard cardB = new CreditCard(222222, "John B");

CreditCard cardC = new CreditCard(111111, "John C");
// cardC.equals(cardA) is true

output.print(cards.add(cardA));
output.println(" " + cards.size());
  
output.print(cards.add(cardB));
output.println(" " + cards.size());
   
output.print(cards.add(cardC));
output.println(" " + cards.size());

The above code fragment prints:

true 1
true 2
false 2

Retrieving Elements

Collections usually provide methods to retrieve elements aggregated by the collection; the exact retrieval mechanism varies depending on the abstraction the collection is trying to provide.

Indexed Retrieval

Some collections associate a non-negative integer index with each element.

Retrieving from Portfolio

Investment get(int index)
Determine the investment in this portfolio with the given index.

Parameters:
index - the number of the investment to get. The index starts at zero and increments as investments are added.
Returns:
the investment whose index is passed.
Throws:
java.lang.RuntimeException - if the index is less than zero or not less than size()

Retrieving from Portfolio

Portfolio pf = new Portfolio("Small Portfolio", 3);

pf.add(new Investment(new Stock("HR.A"), 1, 1.00));
pf.add(new Investment(new Stock("HR.B"), 1, 2.00));
pf.add(new Investment(new Stock("HR.C"), 1, 3.00));

Investment inv = pf.get(0);
output.println(inv);

inv = pf.get(1);
output.println(inv);

inv = pf.get(2);
output.println(inv);

The above code fragment prints:

HR.A ACOMP CORP QTY=1 BV=1.0
HR.B BTECH INC. QTY=1 BV=2.0
HR.C CCOMP CORP QTY=1 BV=3.0

Notice that the order of the Investment references is the same as the order in which they were added to the collection.

Traversing a Portfolio

In general, you would write a loop if you need to visit each Investment.

for (int i = 0; i < pf.size(); i++)
{
   Investment inv = pf.get(i);
   // do something with inv ...
}

Because an index is used to visit each element, this loop is called an indexed traversal of the elements.

Key-Based Retrieval

Some collections allow the client to retrieve an element by specifying a key value; the element corresponding to the key value (if any) is returned.

Retrieving from GlobalCredit

CreditCard get(String number)
Find the card whose number is passed.

Parameters:
number - the number of the card to find.
Returns:
a reference to the card whose number is passed. If the card is not found in the collection, or if the passed number is null, then null is returned.

Retrieving from GlobalCredit

GlobalCredit gc = new GlobalCredit();

gc.add(new CreditCard(111111, "John A"));

CreditCard cc = gc.get("111111-3");
if (cc != null)
{
   output.println(cc.getName());
}

The above code fragment prints:

John A

Notice that when you use key-based retrieval you have to deal with the case where no element in the collection corresponds to the key.

Traversing a GlobalCredit

GlobalCredit does not support index-based traversal. Instead, it supports a generic type of traversal where all that matters is that each element is visited once.

You use a special type of for loop (called the enhanced for loop, or the for-each loop:

GlobalCredit gc = GlobalCredit.getRandom();

for (CreditCard cc : gc)
{
   output.println(cc.getNumber());
}

You read the loop like:

for each CreditCard cc in gc

This type of traversal is called iterator-based traversal because an object (of type Iterator<CreditCard>) that is hidden by the for-each loop is responsible for safely traversing the collection.

Iterator-Based Traversal

Which classes support iterator-based traversal? You need to check the top of the class API:


If the class implements the Iterable interface then you can use a for-each loop.

for-each loops also work with Java arrays.