IB Java Examination Tool Subset (JETS)

Introduction

The IB computer science syllabus requires students to learn Java.  This does not mean all of Java.  With the many libraries and classes, and the constantly changing of the language, that would be impractical.  The intention is not for the students to become Java "experts". Rather Java provides a platform for students to develop and demonstrate their understanding of fundamental algorithm concepts.  Thus students must only learn a small subset of the entire language, referred to as JETS.

Only the commands, symbols, and constructs specified in JETS will appear in examination questions.  Students will not be required to read or write answers involving other libraries.  As the Program Dossier is also written in Java, students will have learned some other constructs and classes, and may choose to use their examination answers.  However, some classes are specifically forbidden, as they contain commands which would perform tasks which IB students are expected to program from simpler constructs.  For example, java.util is forbidden as it contains library commands to perform sorting and searching algorithms.

JETS also specifies a naming convention and style for examination questions.  Teachers should familiarize their students with JETS, including the naming and style conventions.  These conventions are intended to make examination questions clear and easily readable.  Students are not required to follow these conventions in their answers. However, they should write answers in a clear, consistent and readable style, and must not use non-standard libraries which trivialize the solution.

Candidates will not be expected to write perfect syntax in their answers (for example, a mistake in capitalization or a missing semi-colon would not normally be penalized) but errors which substantially change the meaning of the algorithm will be penalized (e.g. "forgetting" an exclamation point is a real error).

Students and examiners alike are expected to use the clearest, most readable style in their answers.  Students should be especially careful to avoid sloppy writing and syntax which is difficult to read, such as double minus signs -- or compound assignment operators like -= .   For example:

           x = x + 1   is clearer than   x++   or   x += 1
           x = x - 1    
is clearer than   x--     or   x -= 1

=============================================================================

The Presentation of JETS

Style Conventions

The style conventions to be used in all examination papers will be as follows:

  • examination questions and general rubric will be printed in Times New Roman (proportional) font (12 point).
    Some general examination rubric will be printed in
    italics.

      JETS-code will be printed in Courier (fixed spacing) font 10.5 point
     

  • all reserved words will be written in lower case bold
  • Class names will always start with a Capital letter
  • instantiations, variable and method names will always start with a small letter
  • mutliWordIdentifiers will use embedded capitals to separate the words (not underscores)
  • identifiers will generally use whole words, not abbreviations or acronyms
  • proper indentation will always be used
  • the order of modules is irrelevant, but the main and/or constructor method will always be placed at the top
  • some examination questions may include statements such as, 'recall that ...'. The intention is to remind candidates of any uncommon commands:    Recall that  String.indexOf(String)  can be used to find the position of one string inside another,
       for example :   
      String  
  • (????) new language elements (libraries) may be explained by writing: 'A library provides the function|subroutine|data-type ...', followed by an explanation and example.
  • for French and Spanish versions of examination papers
    • reserved words will remain in English
    • string constants will be translated
    • user-defined identifiers (variable and subprogram names) will be translated as appropriate.

The Syntax of JETS

Operators

   Arithmetic:    + ,  -  ,  * ,  / ,  % ,  Math.pow(base,exponent)
      //
candidates must understand the polymorphic behavior of the division operator, e.g. int / int ==> int

   Relational:    == ,  > ,  <  ,  >=  ,  <=  ,  !=

   Boolean  :     !  ,   && ,  ||  
     //  bitwise boolean operators  & , |  are not required

 

Operator Precedence

The standards for operator precedence in Java are assumed knowledge.  Examination questions may use extra parentheses for clarity and candidates should be encouraged to do the same in their solutions.

 

Notation for Literals (values)

   String : "in quotation marks"

   integer : 123456 or -312

   double : 124.75 (fixed point) or 1.2475E+02 (floating point)

   boolean : true , false

Constant identifiers will be written in ALL_CAPS, using an underscore to separate words.
They will be defined using
final static, as:

    final static double NATURAL_LOG_BASE = 2.1782818;

 

Primitive Data Types

  byte     int      double     char     boolean        (long and float are not included)

    ---  Wrapper classes Double, Integer, etc.  are not included in JETS.

 

Structured Data Types

  String class

  StringBuffer class

  Linear Arrays :     int[ ]  numbers =  new int[100];      //  array of 100 integers, index 0..99

  2-D arrays:     int[ ][ ]  checkers = new int[8][8];

  Text files  (sequential files)

  Random Access files (fields as primitive types)

 

Parameter Passing

Follows the standard specification in Java, e.g. primitive types are automatically passed by value,
and structured types (arrays and objects) are always passed by reference.

 

Symbols

  /*  multi-line
     comments
  */

  //  single line
  //  comments

  ( )  round brackets for parameters

  [ ]  square brackets for subscripts in arrays

 .    dot notation for dereferencing object methods and data members

  {  }  for  blocks of code

  { 1 , 2 , 3 }   for initializing an array

 

Input/Output (I/O with IBIO)

Java does not provide standard input and output commands as part of the core language.  Instead, I/O is always performed via class libraries.    JETS assumes that some standard input and output commands are available.  It is irrelevant whether these have been implemented as console (text-mode) or event-driven (GUI) commands.  

A suitable set of text-mode methods are provided below, and the IBO may make text-mode and GUI libraries available for teachers.  Exam questions will assume that there are no significant issues in this regard - that is, subtle run-time errors or formatting issues will not be examined.  For example, inputInt might accept scientific notation, as long as the value can be converted to an integer.  This issue will not be examined in algorithm questions, although essay questions about run-time and data-entry errors may be set.

The assumed set of commands is:

    name = inputString("Type anything")    -->  outputs prompt, and returns a string
    age  = inputInt("Type an integer")     -->  outputs prompt, and returns an int
    height = inputDouble("Type a decimal") -->  outputs prompt, and returns a double
 
    output( String )    -->  outputs a String
    output( int )       -->  outputs an int value
    output( double )    -->  outputs a double value
    output( boolean )   -->  outputs a boolean value
    output( char )      -->  outputs a char value
    output( byte )      -->  outputs a byte value
 
    

JETS also uses the System console output commands:

    System.out.print( string )
    System.out.println( string )
 
       //  System.in.read() is not included in JETS

 

Loops and Decisions

   if (boolean condition)
    {
... commands ...}
   else if  (boolean condition)
    {
... commands....}
   else
    {
.... commands .... }  ;                             

             / /   switch..break.. is not included in JETS, but candidates may use it in their answers if they wish.

   for ( start; limit; increment)
    {
...commands...} ;

   while (boolean condition)
    {
...commands...} ;

   do
    {
...commands...}
   while (boolean condition) ;

 

Files

RandomAccessFile

   constructor  randomAccessFile(String filename,String access)
   .seek
   .length
  . read .... readInt, readDouble, readBytes
  . write ....  writeInt, writeDouble, writeBytes
  . close

java.io.*
    BufferedReader(FileReader)  -  
will be used to open a sequential file for input
    PrintWriter(FileWriter)  -  
will be used to open a sequential file for output
    ready
    close

      / /  Serialization is not required.

 

Standard Methods

Math class
*******
    .abs, .pow, .sin, .cos, .round, .floor

String class
********
    + for concatenation,  .equals(String), .substring(startPos, endPos) ,  .length(),  indexOf(String)

??? More String methods ???

(casts)
******
   (int)   (double)   (byte)   

??? More needed here ???

Candidates should be aware that char is a numeric type, arithmetic can be performed directly on chars.

 

Dynamic Memory Allocation

Understanding of the new construct is required.  Candidates must be aware that new causes an object to be instantiated, and that this is somewhat different than declaring a primitive data type.  They should be aware that static methods in some classes can be used without instantiating an object, such as using Integer.parseInt( stringVal )  to convert a string to an integer (without instantiating a new Integer)..  They must also understand that an object type can be declared without instantiating, and that this reference (pointer) can be reassigned later to either a new instance or to a different existing instance.  They should thoroughly understand the rules for scope and lifetime of identifier references, and that instances may be automatically destroyed and garbage collected when they go out of scope.  For example, they must understand that a value stored in a method's local variables will be lost when the method returns, and that this value cannot be retrieved by subsequent calls to the method.  Static is a required concept, but will not be directly tested in code (it may appear, but the meaning will in the code will not be directly examined).

 

Other Syntactical Issues

Java permits commands to span multiple lines.  This may be done in exam questions, but only when it improves clarity and readability, for example in a long parameter list:

public int sortArray( String[ ] names ,
                      int listSize , 
                      char ascendingOrDescending 
                    )

Brackets will always be lined up, either horizontally or vertically:

    public void printNumbers()
    {  int x = 0;
        while ( x < 10 )
        { output( x ); }       //  brackets for the loop body are lined up horizontally
    }                         //  brackets for the method body are lined up vertically

 

Class Scope

Public, Private, Protected

   //  implements and abstract are not included, interface is not included

Overall Structure of Classes

Candidates must understand the concept of a constructor and a main method, and the difference between them.    They must also understand the concept of extends.

Applets will not be examined in coded algorithms, although some concepts of applets (e.g. security) may be examined. 

 

Error Handling

  try{ ...commands... }
  catch(Exception e){ ...handle the error... };
 
// Error handling in exams will be limited to simply outputting an error message, setting a flag, or returning from the method.  
Trapping specific Exception types will not be expected - only the generic EXCEPTION type must be trapped..   methodName() throws IOException // Candidates must understand the idea of throwing an exception, rather than trapping it with try..catch..


Algorithms to Exemplify the Elements of JETS

The examples of algorithms that follow are an attempt to illustrate most of the language elements of JETS.
In the actual examinations, most algorithms will be considerably shorter than these examples.

These were compiled using the Sun JDK 1.3(Java 2).  They run as Console (text-mode) applications, using a standard library of console I/O methods (IBIO).

 =============================================================================

//------ HELLO - demonstrates simplified input/output methods (IBIO)--------

public class Hello
{ public static void main(String[] args)
  { new Hello();}

  public Hello()                               
  { String name = input("What is your name?");
    int age = inputInt("How old are you?");
    int later = age + 7;
    double increase = (((double)later / age - 1) * 100);
    output("Hello " + name);
    output("In 2010, you will be " + later);
    output("That is an increase of " + increase + "%");
    input();                                     // waiting for [enter] key
  }
 //---- IBIO - Below are simplified input and output methods ----

  static void output(String info)
  {  System.out.println(info); }

  static void output(double info)
  {  System.out.println(info);  }

  static void output(long info)
  {  System.out.println(info); }

  static int inputInt(String Prompt)
  {  int result=0;
     try{result=Integer.parseInt(input(Prompt).trim());}
     catch (Exception e){result = 0;}
     return result;
  }

  static double inputDouble(String Prompt)
  {  double result=0;
     try{result=Double.valueOf(input(Prompt).trim()).doubleValue();}
     catch (Exception e){result = 0;}
     return result;
  }

  static String input(String prompt)
  {  String inputLine = "";
     System.out.print(prompt);
     try
     { java.io.InputStreamReader sys = new java.io.InputStreamReader(System.in);
       java.io.BufferedReader inBuffer = new java.io.BufferedReader(sys);
       inputLine = inBuffer.readLine();
     }
     catch (Exception e)
     { String err = e.toString();
       System.out.println(err);
     }
     return inputLine;
  }

  static String input()
  { return input("");  }
}

//-------------------------------------------------------------------------
// The same simplified input/output methods from HELLO are assumed in all  
// the following algorithms.  Rather than reprinting them, a comment
// indicates that they would need to be copied into the program.
//-------------------------------------------------------------------------


//-------------------------------------------------------------
// QUADRATIC finds roots of a quadratic polynomial
//-------------------------------------------------------------   public class Quadratic
{ public static void main(String[] args)
  { new Quadratic();}   public Quadratic()
  { int a = inputInt("A? ");
    int b = inputInt("B? ");
    int c = inputInt("C? ");
    if (isSolvable(a,b,c))
    { output("x1 = " + bigRoot(a,b,c));
      output("x2 = " + smallRoot(a,b,c));
    }
    else
    { output("No roots");}
    input("--- press [enter] ---");
  }     boolean isSolvable(int a, int b, int c)
  { if ((a != 0) && (discriminant(a,b,c) < 0))
    { return false; }
    else
    { return true; }
  }     double discriminant(int a, int b, int c)
  { return b*b - 4*a*c;
  }     double smallRoot(int a, int b, int c)
  { return (-b - Math.pow(discriminant(a,b,c),0.5) ) / (2*a);
  }
 
  double bigRoot(int a, int b, int c)
  { return (-b + Math.pow(discriminant(a,b,c),0.5) ) / (2*a);
  }
  //------------------------------------------------------------ //---- IBIO - include simplified input and output methods ----
//------------------------------------------------------------ }


//-------------------------------------------------------------------
//  NameSaver sample algorithm input a list of names into an array.
//    "XXX" ends the input, then the list is stored in a sequential file.
//  This class does not attempt to handle the possible IOExceptions,
//    (e.g. locked file or full disk drive) but simple "throws" them.
//-------------------------------------------------------------------   import java.io.*;   public class NameSaver
{ public static void main(String[] args) throws IOException
  { new NameSaver();}     String names[] = new String[1000];
  int namesCount = 0;     public NameSaver() throws IOException
  { inputNames();
    saveNames();
  }     void inputNames()
  { String thisName = "";
    namesCount = 0;
    do
    { output("Type a name");
      thisName = input();      
      if (!thisName.equals("XXX"))
      { names[namesCount] = thisName;
        namesCount = namesCount + 1;
      }
    } while (!thisName.equals("XXX") && (namesCount < 1000));
  }     void saveNames() throws IOException
  { PrintWriter outFile = new PrintWriter(new FileWriter("namelist.txt"));
    for (int c = 0; c < namesCount; c++)
    { outFile.println(names[c]);
    }
    outFile.close();
  }
  //------------------------------------------------------------ //---- IBIO - include simplified input and output methods ----
//------------------------------------------------------------ }  
//------------------------------------------------------------------------
//  ENCRYPT Encrypts a string by counting the length, adding that
//    number to the ASCII code of each CAPITAL letter.  Then the result
//    is printed backward.  Only CAPITAL LETTERS get changed.
//      "HOT2Day" --> adding 7 --> "OVA2Kay" --> "yaK2OVA"
//------------------------------------------------------------------------ public class Encrypt
{ public static void main(String[] args)
  { new Encrypt();}     public Encrypt()
  { String message, coded;
    output("Type a message");
    message = input();
    coded = encrypt(message);
    output(reverse(coded));
    input("---- press [enter] ----");
  }     String encrypt(String message)              // Strings are immutable, so
  { int p,num;                                   // use a StringBuffer to
    char codeChar;                               // allow chaning single chars     
    StringBuffer text = new StringBuffer(message);  
    
    num = text.length();
    for(p = 0; p < num; p++)
    { codeChar = addCode( text.charAt(p), num );
      text.setCharAt(p,codeChar);
    }
    return text.toString();
  }     char addCode(char letter,int change)
  { if ((letter >= 'A') && (letter <= 'Z'))      // chars behave like ints, so
    { char oldCode = (char)(letter - 'A') ;      // arithmetic can be performed
      char newCode = (char)((oldCode + change) % 26);        
      return (char)('A' + newCode);              // (char) cast required to      
    } //  avoid warning messages
    else
    { return letter; }
  }     String reverse(String message)
  { String backward = "";
    for(int c = message.length() - 1; c >= 0; c = c-1)  // Count backward
    { backward = backward + message.charAt(c);          
    }                                          // CONCAT won't work with chars
    return backward;
  }  
//------------------------------------------------------------ //---- IBIO - include simplified input and output methods ----
//------------------------------------------------------------ }  
  //---------------------------------------------------------------------
// FileSorter demonstrates the use of a RandomAccessFile to store "records".  
// Java does not contain a specific construct like STRUC or RECORD.  
// An "inner class" can be used for this purpose.  There is no command
// available to read or write "records" to random access files, so these
// must be programmed, writing a single field at a time.
//--------------------------------------------------------------------- import java.io.*;      // contains all the file-oriented classes and methods   public class FileSorter
{ public static void main(String[] args) throws IOException
  { new FileSorter();}     public FileSorter() throws IOException
  { RandomAccessFile ranFile = new RandomAccessFile("Items.dat","rw");
    create(ranFile);
    System.out.println("--- Records before sorting ---");
    display(ranFile);
    sort(ranFile);
    System.out.println("--- Records after sorting ---");
    display(ranFile);
    ranFile.close();
  }     class Item     //------- inner class simulates "records" -----------
  { int id;                            // Item class contains 3 data fields
    String name;                       //  which will be written into and
    double price;                      //  read from the random access file
    final static int NAMELENGTH = 20;                 // constants used to
    final static int RECORDSIZE = NAMELENGTH*2 + 12;  // calculate SEEK values       void readFromFile(RandomAccessFile ranFile, long recordNum)
    //-----------------------------------------------------------
    // Reads one record from ranFile, which must already be open
    // Reads each field - id, price, name use TRIM on NAME to remove
    // padding spaces. IOExceptions are detected and reported
    //-----------------------------------------------------------
    { try                                              
      { ranFile.seek( recordNum * RECORDSIZE);
        id = ranFile.readInt();
        price = ranFile.readDouble();      
        StringBuffer nameBuffer = new StringBuffer(Item.NAMELENGTH);
        nameBuffer.setLength(NAMELENGTH);
        for (int c = 0; c < NAMELENGTH; c++)
        { nameBuffer.setCharAt(c, ranFile.readChar());
        }
        name = nameBuffer.toString().trim();  
      }
      catch(IOException exc)
      { System.out.println("While reading record # " + recordNum);
        System.out.println(exc.toString());
      }
    }       void writeToFile(RandomAccessFile ranFile, long recordNum)
    //-----------------------------------------------------------
    // Writes one record into ranFile, which must already be open
    // IOExceptions are detected and reported
    //-----------------------------------------------------------
    { try         
      { ranFile.seek( recordNum * RECORDSIZE);
        ranFile.writeInt(id);
        ranFile.writeDouble(price);
        ranFile.writeChars(setLength(name,NAMELENGTH));
      }
      catch(IOException exc)
      { System.out.println("While writing " + exc.toString()); }
    }       String setLength(String s,int len)       
    //-----------------------------------------------------------
    // Forces length of string to a specific value
    // Necessary before writing into a random-access file
    //-----------------------------------------------------------
    { StringBuffer sb = new StringBuffer(s);
      sb.setLength(len);
      return sb.toString();
    }
  }  //---- end of Item class -----------------     void create(RandomAccessFile ranFile) throws IOException
  //-----------------------------------------------------------------
  // Puts records into ranFile, which must already be open
  //-----------------------------------------------------------------
  { Item thisRec = new Item();
    for (int c=0; c < 5; c++)
    { thisRec.id = inputInt();
      thisRec.name = input();
      thisRec.price = inputDouble();
      thisRec.writeToFile(ranFile,c);
    }
  }     void display(RandomAccessFile ranFile)
  //-----------------------------------------------------------------
  // Reads all records from ranFile and prints the fields
  //-----------------------------------------------------------------
  { try
    { long recordCount = ranFile.length() / Item.RECORDSIZE;
      Item thisRec = new Item();
      for (int c=0; c < recordCount; c++)
      { thisRec.readFromFile(ranFile, c);
        System.out.println(thisRec.id + ":" + thisRec.name +"="+thisRec.price);      
      }
    }
    catch (IOException exc)
    { System.out.println(exc.toString());}
  }     void sort(RandomAccessFile ranFile)
  //-----------------------------------------------------------------
  // Bubble sort ranFile, sorting name fields in ascending order
  //-----------------------------------------------------------------
  { try
    { long recordCount = ranFile.length() / Item.RECORDSIZE;
      Item thisRec = new Item();
      Item nextRec = new Item();
      for (int pass = 0; pass < recordCount; pass++)
      { for (int pos = 0; pos < recordCount-1; pos++)
        { thisRec.readFromFile(ranFile,pos);
          nextRec.readFromFile(ranFile,pos+1);
          if (thisRec.name.compareTo(nextRec.name)>0)   // comparing strings
          { nextRec.writeToFile(ranFile,pos);
            thisRec.writeToFile(ranFile,pos+1);
          }
        }
      }
    }
    catch (IOException exc)
    { System.out.println(exc.toString());}
  }
  //------------------------------------------------------------ //---- IBIO - include simplified input and output methods ----
//------------------------------------------------------------   }  
  //-------------------------------------------------------------------
//  FactorTree sample algorithm generates a prime-factor tree // This algorithm is for HL candidates only, as binary trees // do not appear in the SL syllabus.
//------------------------------------------------------------------- public class FactorTree
{ public static void main(String[] args)
  { new FactorTree();}     class Node                                 // Use an "inner class" as a
  { int data;                                // Data-Structure similar to a
    Node leftChild;                          // RECORD or STRUC in
    Node rightChild;                         // traditional HL languages
  }     public FactorTree()
  { int number;
    Node root = null;
    number = inputInt("Type an integer:");
    if (number > 2)
     { root = makeTree(number);
       output("The prime factors are");
       showFactors(root);
     }
    output("-----------------");
    outline(root,"");
    input("");
  }     Node makeTree(int number)        // Recursive method to create factor tree
  { Node temp = new Node();        // creates a Node (allocates memory)
    temp.leftChild = null;
    temp.rightChild = null;
    temp.data = number;
    int count = 1;
    int fac = 0;
    while (count*count <= number)
    { if ( (number % count) == 0 )
       { fac = count; }
      count = count + 1;
    }
    if (fac > 1)
    { temp.leftChild = makeTree(fac);
      temp.rightChild = makeTree(number / fac);
    }
    return temp;
  }     void showFactors(Node here)
  { if (here == null) { output("null"); return;}
    if ( (here.leftChild == null) && (here.rightChild == null))
    { output(here.data);
    }
    else
    { showFactors(here.leftChild);
      showFactors(here.rightChild);
    }
  }     void outline(Node here,String indent)        // Pre-order traversal prints
  { output(indent + here.data);                // tree in "outline" format
    if (here.leftChild != null)
     {outline(here.leftChild, indent + "   ");}
    if (here.rightChild != null)
     {outline(here.rightChild, indent + "   ");}
  }
//------------------------------------------------------------ //---- IBIO - include simplified input and output methods ----
//------------------------------------------------------------   }  
  //----------------------------------------------------------------------
// This Calendar class is used by a company for scheduling meetings,
// deadlines, deliveries, etc.  All of the functions will accept dates in
// a variety of formats ("December 25, 2002" or "25 Dec 02" or "12/25/2002")
// but results are always returned in the format "dd MMM yyyy EEE",
// e.g.  "01 Jul 1998 Wed".  This format is also accepted for input parameters.
//----------------------------------------------------------------------   import java.util.*;
import java.text.*;   public class Calendar
{ private static final long ONE_DAY = (long)24*60*60*1000;
    private static final SimpleDateFormat dateFormatter =
                          new SimpleDateFormat("dd MMM yyyy EEE");
    private static final String holidays[] =
    {"01 Jan","01 Apr","01 May","23 Aug","25 Dec","xxxxxx"};     public static String normalDate(String date)
  //--------------------------------------------------------------
  // Determines the day of the week (Mon, Tue, Wed, ...) and    
  // returns DATE in the standard format dd MMM yyyy EEE        
  // For example, normalDate("4/1/2003") --> "01 Apr 2003 Tue"  
  // Returns an empty string "" if DATE is not valid.           
  //--------------------------------------------------------------
  { try{Date df = new Date(date);
        return normalDate(df);}
    catch(Exception e){return "";}
  }     private static String normalDate(Date df)
  { try{return dateFormatter.format(df);}
    catch(Exception e){return "";}
  }     public static int isWorkDay(String check)
  //--------------------------------------------------------------
  // Calls NORMALDATE, to produce dd MMM yyyy EEE.  If WWW is   
  // "Sat" or "Sun", the function returns 0 (false).            
  // Otherwise, it consults a calendar file to check for        
  // holidays, returning 1 for a workday, 0 for a holiday or    
  // weekend, and error code -1 if CHECK is not a valid Date.   
  //--------------------------------------------------------------
  { String d;
    try { d = normalDate(check); }
    catch (Exception e) { return -1; }
      String target = d.substring(0,6);
    String weekday = d.substring(12,15);
    int workday = 1;
    if (weekday.equals("Sat") || weekday.equals("Sun"))
    { workday = 0; }
    else
    { int c = 0;
      while (c<5)
      { if (target.equals(holidays[c]))
        { workday = 0; }
        c = c+1;
      }
    }
    return workday;
  }       public static String nextDay(String date)
  //--------------------------------------------------------------
  // Accepts DATE in various formats, returns the next date in  
  // standard format dd MMM yyyy EEE. Returns an empty string  
  //  if DATE is not valid (e.g. 1998.37.58)                    
  // This correctly accounts for end of the month, end of year,
  // leap years, etc. For example:                              
  //      NEXTDAY("28 Feb 1998 Sat") ----> "01 Mar 1998 Sun"    
  // Returns an empty string if DATE is not valid.              
  //--------------------------------------------------------------
  { return normalDate(new Date(new Date(date).getTime() + ONE_DAY));
  }     public static int daysBetween(String first,String second)
  //--------------------------------------------------------------
  // Counts the number of days between two dates, including the
  // ends.  If FIRST is after SECOND, returns a negative number.
  // IF FIRST and SECOND are the same date, returns 1.          
  // If FIRST or SECOND are not valid, returns error code 0     
  //--------------------------------------------------------------
  { try
    {Date d1 = new Date(first);
     Date d2 = new Date(second);
     return (int)( (long)(d2.getTime() - d1.getTime()) / ONE_DAY);
    }
    catch(Exception exc)
    { return 0; }
  }     public static String today()
  //--------------------------------------------------------------
  // Returns today's date in standard format dd MMM yyyy EEE    
  //--------------------------------------------------------------
  { try
    { Date now = new Date();
      return normalDate(new Date(now.getYear(),now.getMonth(),now.getDate()));
    }
    catch (Exception exc)
    { return ""; }
  }
}   //------------------------------------------------------------------------
// By providing PUBLIC STATIC Methods, another class can use
// these methods without instantiating an object, thus providing similar
// funcionality to traditional library procedures.  Notice that
// reusability and reliability are improved by careful exception handling.
// In an exam question, only the method headers and comments need be
// provided the candidates do not need to know HOW the methods work.
//------------------------------------------------------------------------
 
  //---------------------------------------------------------------------
// WORKDAYS sample algorithm inputs two dates, and counts the number
//   of workdays between the two dates, including the ends.
//   It IMPORTS the Calendar class, so it can use its methods.
//---------------------------------------------------------------------   import Calendar;    // see previous pages   public class WorkDays
{ public static void main(String[] args)
  { new WorkDays();}     public WorkDays()
  { String first,last,temp;
    int between;
    output( "This algorithm counts the workdays between two dates.");
    
    first = "";
    while (first.equals(""))               // bad date returns empty string
    { output("Type in the first date:");   // Loop until good date entered
      first = input();
      first = Calendar.normalDate(first);
    }
    
    last = "";
    while (last.equals(""))                // bad date returns empty string
    { output("Type in the last date");     // loops until good date entered
      last = input();
      last = Calendar.normalDate(last);
    }     between = Calendar.daysBetween(first,last);
    if (between < 0)
    { temp = first;           // Swap FIRST and LAST - they are out of order
      first = last;
      last = temp;
    }
   
    between = Calendar.isWorkDay(first);
    output(first);
    while (!first.equals(last))          // Don't use == to compare strings
    { first = Calendar.nextDay(first);
      between = between + Calendar.isWorkDay(first);
      output(first);
    }
    output(between + " workdays between " + first + " and " + last );
  }
//------------------------------------------------------------ //---- IBIO - include simplified input and output methods ----
//------------------------------------------------------------ }
  //----- Sample Output ------------------------------------
  This algorithm counts the workdays between two dates.
  Type in the first date:
  12/21/2002
  Type in the last date
  12/31/2002
  21 Dec 2002 Sat
  22 Dec 2002 Sun
  23 Dec 2002 Mon
  24 Dec 2002 Tue
  25 Dec 2002 Wed
  26 Dec 2002 Thu
  27 Dec 2002 Fri
  28 Dec 2002 Sat
  29 Dec 2002 Sun
  30 Dec 2002 Mon
  31 Dec 2002 Tue
  6 workdays between 31 Dec 2002 Tue and 31 Dec 2002 Tue //----- end Sample Output -------------------------------