Google
 
Site navigation: [ Home | Theory | Java | About ]

Records in Java

Most, if not all, business/commercial applications of computer systems are using record-type data handling processes.

Field names at the top

Individual records

An important element of record structure is that each field holds data of a specified type .

These diagrams are also found in the book Computer Science although it originated on the ib-computing.com website.

IBID Press Complete coverage of the IB Computer Science Program in a textbook by Richard Jones & Andrew Meyenn .

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Here I've used a convention of putting vt before the data fields and fd for the fields that just label the fields.

It makes life easier for me and for other people reading the code.

To put the labels close to the data fields I used right-justification ( Label.RIGHT ).Simple set of actions

 

 

Messages as usual...

 

VideoTape is the inner class, defined later in the code. We use an array of these objects to store the data.

This could be handled much better in a real application. There is no scope for the user to change them.

 

 

 

 

Data members of inner class.

Constructor that sets data fields.

I've scrunched these up to save space in the listing.

 

 

Remember the use of the this keyword to make sure we are returning the Class data member and not any local identifiers .

Notice the semi-colon at the end of the inner class definition.

 

 

 

 

 

The layout was achieved through the use of Panels and a lot of trial and error.

 

 

 

 

 

BorderLayout defines 5 areas of the container surface: CENTER, NORTH, SOUTH, EAST and WEST where Panels or objects can be placed.

Button listeners

 

 

 

 

 

add Button was pressed.

Get the details from the fields the user has (hopefully) filled in.

Check there is more space to store details.

 

Add the tape at the end.

let the user know.

 

 

Something went wrong in getting the details (see later).

If else chain - the Next button.

Display record at element current (zero-based, so adjust message to a more natural "human" concept).

 

 

Similar checks for moving backwards through the collection.

 

 

 

 

 

 

 

This method call is used at the end of the init() method.

It adds itesm from the DESC array to the Choice list box.

Notice the return type of VideoTape - our inner class.

If these fields are empty the tape is not valid.

 

 

 

Possible exceptions are bad number format for the expected integer and there being no item selected in the drop down list.

 

 

 

Given the position of a valid record in the display, this method displays it.

Notice that collection[current] is of type VideoTape.

A special method is required to convert from stored code to descriptions in the Choice list.

Use of vt prefix helps us to remember which GUI object the identifier refers to.

 

 

 

 

 

Simple search of the array.

If we find the code. return the corresponding description.

 

 

 

 

 

The Applet in action, not very good yet, but something to build on.

Refer to the classes page if neccessary to find out how to create a custom class.

 

 

 

Technically, not showing how to do this could be regarded as a cop out!

You can also add special validation checks (see if the tape length is reasonable, for example).

If the inner class adds all these techniques then we end up with very cluttered code.

 

 

 

 

 

This is a hard exercise but if you succeed you can practically write a Standard Level Dossier right now.

All you need is files (da, da, dada da).

Well, maybe searching or sorting too...

On this page: [ the concept | as inner classes | as separate classes | database example ]

Records - the concept

Sometimes data items of different types belong logically together. For example, all of the data about a student in a school could be held in a single object known as a record . Traditional programming languages and applications such as databases provide ways of grouping such data together. The following terminology is associated with records:

The fields are in italic type and the DATA is in CAPITALS . All three records together would make up a data file.

The same information can often be presented in column layout, when all three records can be seen together with the fields used as labels at the top of each column:

FORENAME SURNAME BIRTHDATE SEX   FORM
Frederick Handel 12/03/1685 M   10T
Robert Schumann 08/06/1810 M   8R
Jean Cage 19/07/1912 F   13E

Now the file is represented by all of the information in the table . The data in each field can be of any primitive type or of other classes too. Traditional languages provide data structures called records which allow data to be kept together as a single unit:

  newtype StudentRecord Record

     Forename string
     Surname string
     BirthDate string
     Sex character
     Year integer
     Form character

   endrecord

However, since Java is already based around the idea of grouping objects with a common structure we can simply define a class and any associated methods needed to access the data associated with each object created.

This class can be an explicit class, like the Fraction Class we saw already, or it can be an "inner class" - that is, combined with an existing Class. We look at both of these methods

Back to top

Inner Classes

In the listing: [ Class definition | inner class | init/actionPerformed | helper methods ]

The Class definition and data members are as follows:

import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;

/**
* This Applet demonstrates an inner class being used for data records
* The inner class keeps data about video tapes
*
* @ Mr J
* @ 20040308
*/

public class VideoTapeInner extends Applet implements ActionListener
{
   // display fields for record data
   private TextField vtTitle = new TextField(25);
   private TextField vtLength = new TextField(6);
   private Checkbox vtLent = new Checkbox();
   private Choice vtType = new Choice();

  // labels for field data
   private Label fdTitle = new Label("Video title:", Label.RIGHT);
   private Label fdLength = new Label("Length (min):", Label.RIGHT);
   private Label fdLent = new Label("Lent:", Label.RIGHT);
   private Label fdType = new Label("Type:", Label.RIGHT);

  // control buttons
   private Button add = new Button("add tape");
   private Button next = new Button("next");
   private Button prev = new Button("previous");

  // system messages display
   private Label messages = new Label("System messages will appear here");

  // Set up an array to hold the tape collection
   private static final int MAX_TAPES = 5;
   VideoTape[] collection = new VideoTape[MAX_TAPES];
   private int last = -1;      // pointer to last record in collection
   private int current = -1;   // pointer to record in display

   // define the possible movie types (could be more flexible):
   static final int ROMANCE = 0;
   static final int COMEDY = 1;
   static final int ACTION = 2;
   static final int[] TYPE = { ROMANCE, COMEDY, ACTION};
   static final String[] DESC = {"Romance", "Comedy", "Action"};
   static final char[] CODE = {'R', 'C', 'A'};

Back to top        top of listing

Next we define the inner class, it's pretty much the same as defining any Class in an external file:

  class VideoTape
   {
     private String title;
     private int length;
     private boolean lent;
     private char type;
 
    // Constructors
     public VideoTape() { super(); }
     public VideoTape( String title, int length, boolean lent, char type )
     {
       setTitle( title );
       setLength( length );
       setLent( lent );
       setType( type );
     }
 
    // mutator methods, could include data validation
     public void setTitle( String title ) { this.title = title; }
     public void setLength( int length ) { this.length = length; }
     public void setLent( boolean lent ) { this.lent = lent; }
     public void setType( char type ) { this.type = type; }
     
// accessor methods
     public String getTitle() { return this.title; }
     public int getLength() { return this.length; }
     public boolean isLent() { return this.lent; }
     public char getType() { return this.type; }
   };
// end of inner class definition

Back to top        top of listing

The init and actionPerformed methods are pretty standard by now:


/**
* Add objects to the Applet
*/

public void init()
{
   Panel recordPanel = new Panel();
   recordPanel.setLayout( new GridLayout(4, 2, 10, 10) );
   recordPanel.add(fdTitle);
   recordPanel.add(vtTitle);
   recordPanel.add(fdLength);
   recordPanel.add(vtLength);
   recordPanel.add(fdLent);
   recordPanel.add(vtLent);
   recordPanel.add(fdType);
   recordPanel.add(vtType);

   Panel buttonPanel = new Panel();
   buttonPanel.setLayout( new GridLayout(3, 1, 10, 10) );
   buttonPanel.add(add);
   buttonPanel.add(prev);
   buttonPanel.add(next);

   setLayout( new BorderLayout(25, 25) );
   setSize(400, 180);
   add(recordPanel, BorderLayout.CENTER);
   add(buttonPanel, BorderLayout.EAST);
   add(messages, BorderLayout.SOUTH);

   add.addActionListener(this);
   prev.addActionListener(this);
   next.addActionListener(this);
   // set up the choice list
   setUpChoices();
}
/**
* When an event occurs on an object with an ActionListener attached, this
* method is carried out.
*
* @param e carries details about the event that occurred
*/
public void actionPerformed(ActionEvent e)
{
   if (e.getSource() == add)
   {
     // add a new video tape to the collection
     VideoTape theTape = getTapeDetails();
     if (theTape != null)
     {
       last = last + 1;
       if (last == MAX_TAPES)
       {
         messages.setText("No more space to store tapes");
       }
       else
       {
         collection[last] = theTape;
         current = last;
         messages.setText("tape added");
         clearDisplay();
       }
     }
     else
     {
       messages.setText("Invalid tape details");
     }
   }
   else if (e.getSource() == next)
   {
     if (current < last)
     {
       current = current + 1;
       setDisplay(current);
       messages.setText("At tape " + (current + 1) + " of " + (last + 1));
     }
     else
     {
       messages.setText("At last record");
     }
   }
   else if (e.getSource() == prev)
   {
     if (current > 0)
     {
       current = current - 1;
       setDisplay(current);
       messages.setText("At tape " + (current + 1) + " of " + (last+1));
     }
     else
     {
       messages.setText("At first record");
     }
   }
}

Back to top        top of listing

Now we move on to the helper methods:

  /**
   * set up some types in the choice list
   */

    private void setUpChoices()
   {
     for (int i = 0; i < TYPE.length; i++)
     {
       vtType.addItem(DESC[i]);
     }
   }

   /**
   * collect tape details and create new tape
   *
   * @return a VideoTape object - null if details are invalid
   */
   private VideoTape getTapeDetails()
   {
     try
     {
       String title = vtTitle.getText();
       int length = Integer.parseInt(vtLength.getText());
       boolean lent = vtLent.getState();
       char type = vtType.getSelectedItem().charAt(0);

       if ( (title.length() == 0) || (length == 0) )
       {
         return null;
       }
       return new VideoTape(title, length, lent, type);
     }
     catch(Exception e)
     {
       return null;
     }
   }
   /**
   * display tape details
   *
   * @param the current VideoTape object
   * pre: current refers to a valid element in the collection array
   *      and this element must point to a VideoTape instance
   */

   private void setDisplay(int current)
   {
     vtTitle.setText(collection[current].getTitle());
     vtLength.setText("" + collection[current].getLength());
     vtLent.setState(collection[current].isLent());
     vtType.select(getTypeDescription(collection[current].getType()));
   }
  /**
   * clear record display panel
   */

   private void clearDisplay()
   {
     vtTitle.setText("");
     vtLength.setText("");
     vtLent.setState(false);
     vtType.select(0);
   }
  /**
   * Given a code, return the corresponding description
   *
   * @param the code to look up
   * @returns a String with the description (or none)
   * pre: There exists a description in the DESC array corresponding to
   *      the element containing code in the CODE array.
   */

   private String getTypeDescription(char code)
   {
     int pos = 0;
     boolean found = false;
     while ( (pos < CODE.length) && !(found) )
     {
       found = (CODE[pos] == code);
       pos = pos + 1;
     }
     if (!found)
     {
       return "none";
     }
     else
     {
       return DESC[pos-1];
     }
   }

Back to top        top of listing

source code for VideoTapeInner.

Record Classes

Actually, you should be able to do this easily enough. All that is required is to take (cut and paste) the inner Class code out of the Applet and create a new VideoTape.java class file.

This won't need any GUI objects or Applet methods. In BlueJ the Applet will automatically link to the new VideoTape Class.

The advantages of having a completely separate Class are:

  • Easier to test and debug
  • Smaller blocks of code are easier to understand
  • Code can be re--used

Further Exercises

You should also be able to add a custom exception class VideoTapeException if you followed the earlier pages on this technique. You would then need to change the Applet code which adds a new tape to the collection to catch these exceptions - you might find it easier to put these into an addTape() helper method.

Custom exceptions you could create could be:

  • No title
  • Tape length not a number
  • Bad tape length (less than zero, for example)
  • Title exceeds allowable number of characters

The different types of video tape should be extendable easily by the user. One way to do this is to have the VideoTape Class keep an array of type CODE and DESC arrays internally. You would need to provide a mechanism to add data to these arrays.

One possible way to do this is to have a Panel with code and description TextFields in the NORTH of the Applet layout. You could add an "Add Type" Button which collects the data and adds it to the arrays in Class VideoTape (perhaps using a public addType() method).

Back to top

Related: [ Java home | Biscuits database example ]

Databases such as Access, Paradox and mySQL are general purpose applications which are often used to handle data records.



NEWISH:

I went over the whole object/record/database type app with my class back in Nov 2004.

Feel free to follow along on these pages.

They relies quite heavily on BlueJ but could be adapted.

 

 
The site is partly financed by advertising revenue, partly by online teaching activities and partly by donations. If you or your organisation feel these resouces have been useful to you, please consider a donation, $9.95 is suggested. Please report any issues with the site, such as broken links, via the feedback page, thanks.

Questions or problems related to this web site should be addressed to Richard Jones who asserts his right to be identified as the author and owner of these materials - unless otherwise indicated. Please feel free to use the material presented here and to create links to it for non-commercial purposes; an acknowledgement of the source is required by the Creative Commons licence. Use of materials from this site is conditional upon your having read the additional terms of use on the about page and the Creative Commons Licence. View privacy policy.

Creative Commons License


This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 2.5 License. © 2001 - 2009 Richard Jones, PO BOX 246, Cambridge, New Zealand;
This page was last modified: October 28, 2013