1. Miscellaneous Java constructs:
    1. Parameter Passing
    2. Arrays:
    3. More Strings:
  2. Pre & Post-conditions
  3. Vectors

Miscellaneous Java constructs:

Parameter Passing

All parameters in Java are passed by value. That is, any assignment to a parameter inside a method body is forgotten when the method returns.

Luckily, can send messages to object parameters. If this changes the state (fields) of an object, this will be remembered when return.

Common restriction in pure OO languages (but not C++). Necessary in order to use subtyping in a type-safe way.

Result is use more functions in OO languages or procedures which send messages changing state of parameters (without assigning to them).

Arrays:

All arrays begin at 0, and referred to through familiar a[index] notation.

Declare arrays:

int[] scores;

Button[] controls;

Never include the size of the array in the declaration:

int[10] scores // Illegal in Java!

Instead, arrays are objects and must be instantiated (created) like other objects:

int[] scores = new int[10];

or, if already declared, just

scores = new int[10];

Results in scores[0], scores[1],..., scores[9].
Notice difference between size of array and last subscript!

Every array knows its size, thus scores.length will return 10
-- length is a field, not a method, so needs no "()" after it.

Array elts are scores[0],..., scores[scores.length-1]

Thus could have used buttonNum < scores.length in for loop.

Java supports array expressions, which can be used to initialize arrays:

int a[] = {1,2,3,4,13};

initializes a to be an array of 5 integers (with indices 0 to 4).

Like Pascal, Java does not support multi-dimensional arrays.

Like Pascal, Java does support arrays of arrays (though with less syntactic sugar).

int[][] table;

is equivalent to

(int[])[] table

That is, table is an array of arrays of integers.

Unlike Pascal cannot write subscripts separated by ",", must write table[3][5].

table = new int[10][15];

creates table as 2-dim'l array.

Can also do trickier things like create 2-dim'l array of elts where successive rows have different numbers of elements. See text for examples.

Clarification on "call-by-value": If pass an array as a parameter, can't assign to the array, but can assign to the values and they will be remembered when return!


More Strings:

Strings are objects and are constants (not updatable!).

Many built-in string functions (see web page), such as

    public int length();
    public char charAt(int index);  
        // Require 0 <= index < length, o'wise raise exception
    public boolean equals(Object anObject);     
    public boolean equalsIgnoreCase(String anotherString);  
    public int compareTo(String anotherString);     
        // returns neg, 0 or pos int depending on comparison 
    public int indexOf(int ch)  
        // index of first occurrence of ch or -1 if not there
If want updatable strings, see StringBuffer class.

String is not an array of char, but can convert from one to other using methods.

Check Point:

At this point, all of chapters 3 & 4 of Core Java (except packages) and Chapter 1 of Bailey should make sense to you. That is, I haven't lectured about them, but you should be able to read them and understand what is there.

Pre & Post-conditions

Now to Bailey's text .

You will have noticed that at the top of most of my methods, I have notations like:

/**
    pre: .....
    post: ....
**/

These comments set out a contract for the use of a particular method. For instance, see the following code:

/**
    pre:  0 <= index < this.length()
    post:  returns character at "index" position 
(starting count from 0) in this **/ public char charAt(int index) {...}

The contract expressed by the pre and post-conditions is that the implementer promised that the post-condition will be true after executing the method, as long as the user promises that the pre-condition will be true when it is called. Thus both the caller and the implementer have responsibilities under the contract.

For the above example, the user is required to specify an index which is legal for the string (between 0 and myString.length() - 1, inclusive), and if the user meets that commitment, the implementation promises to return the character in the "index" position of myString.

It is useful having these as comments, but often it is much more useful to have them checked at run-time, as if any fail, it is indication of an error in the program.

Moreover, the location of the failure is more likely to provide a pointer to the source of the error than just getting a wrong answer (or system crash).

Thus, there is a class in the provided "structure" library which contains methods to check these at run-time.

public class Assert {
    // pre: result of precondition test is true or false.
    // post: does nothing if test true, otherwise abort     
    //  w/message
    static public void pre(boolean test, String message)

    // pre: result of postcondition test is true or false.
    // post: does nothing if test true, otherwise abort 
    //  w/message
    static public void post(boolean test, String message)
 
    // pre: result of general condition test is true or false.
    // post: does nothing if test true, otherwise abort 
    //  w/message
    static public void condition(boolean test, String message)

    // post: throws error with message
    static public void fail(String message)
}

Thus if we were writing the code for charAt above, we could write:

public char charAt(int index)
{ Assert.pre(0 <= index && index < length(),
                                "Index out of bounds for string");
    ...
    Assert.post(..., "post condition error");
}

If either of the boolean conditions is false at the time they are executed then the system will raise an exception (i.e., crash) and print a message telling that a pre- (or post-) condition failed and give the error message.

Sometimes pre- and post-conditions can't be expressed concisely or efficiently (e.g., how do you say "array is sorted"), so may not be able to put in code. Make sure that don't call the routine recursively to get in non-terminating computation in checking pre- or post-conditions. In these cases, use comments for pre- and post-conditions.

Eiffel is an OO language with built-in support for pre- and post-conditions. It also has compiler switches which can be turned on and off to determine whether or not pre- and post-conditions are checked (default is pre-conditions only checked).

I expect all methods to be decorated with pre and post-conditions in comments, and in code where it makes sense.

Vectors

Last time talked about the use of arrays.

Can create arrays of any fixed size, but can't change size aside from creating an entirely new array.

Built-in class Vector allows user to build something like an array, but can change size dynamically. Can add new elts or delete elts anywhere in vector.

Vector holds elements of type Object, hence must use casts when take out elements to do anything useful with them (unlike arrays!)

Below is listing of many of methods in implementation of Vector in structure library (which mimics the one in java.utilities).

public class Vector
{
    // post: constructs a vector with capacity for 10 elements
    public Vector()

    // pre: initialExtent >= 0
    // post: constructs an empty vector with initialExtent 
    //  capacity
    public Vector(int initialExtent)

    // pre: initialExtend >= 0, extentIncrement >= 0
    // post: constructs an empty vector with initialExtent 
    //  capacity that extends capacity by extentIncrement, or 
    //  doubles if 0
    public Vector(int initialExtent, int extentIncrement)

    // post: adds new element to end of possibly extended 
    //  vector
    public void addElement(Object obj)
 
    // post: returns true iff Vector contains the value
    //  (could be faster, if orderedVector is used)
    public boolean contains(Object elem)

    // pre: dest has at least size() elements
    // post: a copy of the vector is stored in the dest array
    public void copyInto(Object dest[])

    // pre: 0 <= index && index < size()
    // post: returns the element stored in location index
    public Object elementAt(int index)

    // pre: vector contains an element
    // post: returns first value in vector
    public Object firstElement()
 
    // post: returns index of element equal to object, or -1.  
    //  Starts at 0.
    public int indexOf(Object elem)

    // post: returns index of element equal to object, or -1.  
    //  Starts at index.
    public int indexOf(Object elem, int index)

    // pre: 0 <= index <= size()
    // post: inserts new value in vector with desired index
    //   moving elements from index to size()-1 to right
    public void insertElementAt(Object obj, int index)

    // post: returns true iff no elements in the vector
    public boolean isEmpty()
 
    // pre: vector is not empty
    // post: returns last element of the vector
    public Object lastElement()
  
    // post: returns index of last occurrence of object in the 
    //  vector, or -1
    public int lastIndexOf(Object obj)

    // pre: index >= 0
    // post: returns the index of last occurrence of object at  //  or before index.
    public int lastIndexOf(Object obj, int index)
  
    // post: vector is empty
    public void clear()

    // post: vector is empty
    public void removeAllElements()
 
    // post: remove first element of vector equal to parameter 
    //  Move later elts back to fill space.
    public boolean removeElement(Object element)

    // pre: 0 <= where && where < size()
    // post: indicated element is removed, size decreases by 1
    public void removeElementAt(int where)

    // pre: 0 <= index && index < size()
    // post: element value is changed to obj
    public void setElementAt(Object obj, int index)

    // post: returns the size of the vector
    public int size()
}

Vectors are generally used any time size of an array must change dynamically. One example is in paint programs where new objects added. See SimpleDraw.