Indexed Properties

So far we have been talking about properties that have only one value. For each named property, we have a single associated value. But this is not always the best way to represent properties; sometimes a property is better modeled as having multiple values. You can create properties that are actually an ordered collection of values associated with a single name. The individual values are accessed using an integer index, much the same way you would with an array.

There is an additional design pattern for indexed properties. The <PropertyType> in the standard property method design pattern may be an array, as follows:

public <PropertyType>[] get<PropertyName>();
public void set<PropertyName>(<PropertyType>[] value);

These methods are used to access the entire array of property values at one time. An additional method can be used to provide access to individual values in the property array. The method signatures for this pattern are:

public <PropertyType> get<PropertyName>(int index);
public void set<PropertyName>(int index, <PropertyType> value);

As with the single value pattern, these methods are allowed to include a throws clause for throwing checked exceptions. Specifically, the indexed methods may throw a java.lang.ArrayIndexOutOfBoundsException if an index is used that is outside the bounds of the property array. Although this is an important aspect of indexed properties, it isn’t required for the indexed properties pattern. Since the indexed properties are considered ordered collections, I think the indexed get() and set() methods should always declare the ArrayIndexOutOfBoundsException. It might have been better to make it a requirement for this pattern.

Imagine that we are building a system that tracks stock prices in real time. First, let’s think about building a watch list object that keeps track of prices for a set of stocks. We’ll call this class a WatchList. We then define a property of the WatchList called Stocks which contains a list of stocks for which prices are being tracked. The type of the Stocks property is a String array, and each individual stock is represented by a String. We also implement a read-only property called StockCount that returns the number of stocks in the WatchList. The code looks like this:

import java.util.*;

public class WatchList
{
   // a vector that contains the actual stock names
   protected Vector stocks = new Vector();
   
   // constructor
   public WatchList()
   {
   }

   // the get method for the StockCount property
   public synchronized int getStockCount()
   {
      // the StockCount property is derived from the size of the
      // stocks Vector
      return stocks.size();
   }

   // get method for Stocks property array
   public synchronized String[] getStocks()
   {
      // we don't currently deal with the case where the watch list
      // is empty

      // allocate an array of strings for the stock names
      String[] s = new String[getStockCount()];

      // copy the elements of the stocks Vector into the string array,
      // and then return the array
      stocks.copyInto(s);
      return s;   
   }

   // set method for Stocks property array
   public synchronized void setStocks(String[] s)
   {
      // the existing list of stocks is removed in favor of the
      // new set of stocks

      // set the size of the stocks vector to match the length
      // of the new array
      stocks.setSize(s.length);

      // copy the values into the stocks vector
      for (int i = 0; i < s.length; i++)
      {
         // use the single stock set method
         try
         {
            setStocks(i, s[i]);
         }
         catch (ArrayIndexOutOfBoundsException e)
         {
         }
      }
   }

   // get method for single element of Stocks property
   public synchronized String getStocks(int index)
               throws ArrayIndexOutOfBoundsException
   {
      // make sure the index is in bounds
      if (index < 0 || index >= getStockCount())
      {
         throw new ArrayIndexOutOfBoundsException();
      }

      // get the stock and return it
      String s = (String)stocks.elementAt(index);
      return s;
   }

   // set an individual element of the Stocks property array
   public synchronized void setStocks(int index, String stock)
               throws ArrayIndexOutOfBoundsException
   {
      // make sure the index is in bounds
      if (index < 0 || index >= getStockCount())
      {
         throw new ArrayIndexOutOfBoundsException();
      }
      
      // change the stock at the specified index
      stocks.setElementAt(stock, index);
   }
} 
            

Get Developing Java Beans now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.