Greetings...

Java Take-Off Step One:

ENTERING THE JAVA JUNGLE


A little welcome, a few warm-ups

The On-line Java Tutorial provides clear and complete directions for installing Java on your computer.

Documentation is available here (from there you can find the API Overview).

Next, we'll delve into the specifics of the Java language.

First, here's a program working with 2D arrays of characters:

import java.lang.*;

public class CheckerBoardTest
{
    // constant value for the width and height of the board 
    public static final int  SIZE   = 8;
    
    // character that represents a blank square 
    public static final char PLAIN  = ' ';
    
    // character that represents a shaded square  
    public static final char SHADED = 'S';
    
    // 2-D array of character data for the checkerboard  
    private char[][] board;
    
    // fills in the board with shaded and plain square values  
    public CheckerBoardTest()
    {
	// create an array of 9 values for one row of squares
	// this array will be copied from 0-7 or 1-8 
	final char[] values = { PLAIN, SHADED, PLAIN, SHADED,
				PLAIN, SHADED, PLAIN, SHADED, PLAIN };
	
	// allocate memory for the checkerboard           
	board = new char[SIZE][SIZE];
	
	// copy the array of square values to each row of squares
	// even rows will start at 0; odd rows will start at 1 
	for(int i = 0; i < SIZE; i++)
	    {   
		System.arraycopy(values, i%2, board[i], 0, SIZE);
	    }
    }
    
    // prints the state of the game board to the console  
    public void print()
    {
	for(int i = 0; i < SIZE; i++)
	    {
		for(int j = 0; j < SIZE; j++)
                    {
			System.out.print(board[i][j]);
                    }
		// print blank line between rows 
		System.out.println();
	    }
    }
    
    // creates a CheckerBoard object and print it to the console       
    public static void main(String[] args)
    {
	new CheckerBoardTest().print();
    }
} // CheckerBoardTest  

EXERCISES

Here's another program that simulates the flipping of a coin until the user decides to quit.

import java.io.*;

public class CoinTossTest
{
    // String representation of each side of a coin
    static final String[] faces = { "Heads", "Tails" };
    
    public static void main(String[] args) throws IOException
    {
	// create a reader to read user input
	BufferedReader reader = 
	    new BufferedReader(new  
		InputStreamReader(System.in));                
	
	// guarantees that we perform the loop at least once
	do   
	    {
		// generate a 0 or a 1
		int result = (int)Math.round(Math.random());
		
		// print the result
		System.out.print(faces[result] + 
				 " it is! Toss again (Y/N)?  ");
	    }
	// quit when user does not input "y" or "Y"
	while(reader.readLine().toUpperCase().equals("Y"));
	
    } // main
} // CoinTossTest

EXERCISES

Here's a fairly inefficient (though crystal clear) program that handles exceptions:
import java.io.*;

public class PrimeFactorsTest
{
    // reads a String from the user and converts it to an int
    public static int readInt(String prompt) throws IOException
    {
	int result = 0;  // the value read from the user
	
	// create a new BufferedReader to read from standard input
	BufferedReader reader = 
            new BufferedReader(
                new InputStreamReader(System.in)); 
	
	// print out the user prompt
	System.out.print(prompt);
	
	// attempt to read until valid input is entered
	while(true) 
	    {
		try
                    {
			// parse the input into an integer
			result = Integer.parseInt(reader.readLine());
			return result;
                    }
		catch(NumberFormatException e)
                    {
			// ask the user to re-enter the data
			System.out.print("Bad number format, redo: ");
                    }
	    } 
    } // readInt
    
    // brute-force determination of whether a number is prime 
    // (has no factors other than itself and one)
    public static boolean isPrime(int n)
    {
	for(int i = 2; i < n; i++)
	    {
		// once we find a factor, we're done
		if(n%i == 0)
                    {
			return false;
                    }
	    }
	// no factors!
	return true;
    }
    
    // brute-force method to find all of the prime factors of a number: not
    // only must a number be a factor or n, but it also must be prime as well
    public static void printPrimeFactors(int n, int start)
    {
	for(int i = start; i < n; i++)
	    {
		if(n%i == 0 && isPrime(i))
                    {
			System.out.print(i + " ");
                    }
	    }
    }
    
    public static void main(String[] args) throws IOException
    {     
	// read in values until the user wants to quit               
	int n = readInt("Enter a number, or -1 to quit: ");
	
	while(n > 0)
	    {
		System.out.print(n + " : ");
		printPrimeFactors(n, 2);
		System.out.println();
		n = readInt("Enter a number, or -1 to quit: ");
	    }
    } // main
    
} // PrimeFactorsTest
EXERCISES Here's a collection of three classes that simulate a deck of cards.

First, here's how we model a card (Card.java):

public class Card
{
    // array representing all possible face values 
    public static final String[] FACES 
	= { "2", "3", "4", "5", "6", "7", "8", "9", "10",
	    "J", "Q", "K", "A" };
    
    // array representing all possible suit values
    public static final String[] SUITS 
	= { "Hearts", "Spades", "Clubs", "Diamonds" };
    
    // the maximum number of cards that can be indexed
    public static final int MAX_CARDS = FACES.length * SUITS.length;
    
    // the value assigned to this Card
    protected int value;
    
    // creates a default Card with a value of 0
    public Card()
    {
	value = 0;
    }
    
    // creates a Card indexed by n.  
    // invalid indexes will cause the program to terminate
    public Card(int n)
    {    
	if(n < 0 || n >= MAX_CARDS)    
	    {
		System.out.println("Error: Invalid Card Index (" +
				   n + "). Program terminating.");
		
		System.exit(0);
	    }
	
	else
	    {
		value = n;    
	    }
    }
    
    // returns the String representation of this Card's face value
    public String getFace()
    {
	return FACES[value%FACES.length];
    }
    
    // returns the String representation of this Card's suit value 
    public String getSuit()
    {
	return SUITS[value%SUITS.length];
    }
    
    // returns the String representation of this Card
    public String toString()
    {
	return getFace() + " of " + getSuit();
    }
    
} // Card
Here's the next level, a deck of cards (Deck.java):
import java.util.*;

// represents a deck of cards of any size
public class Deck
{
    // a stack of Card objects
    protected Stack cards;
    
    // a collection of all drawn cards
    protected List drawnCards;
    
    // allows random retrieval of cards in the above List
    protected Random random;
    
    // creates a Deck of the given size 
    public Deck(int size)
    {
	// push the sent number of Cards onto the stack
	cards = new Stack();
	for(int i = 0; i < size; i++)
	    {
		cards.push(new Card(i));
	    }
	
	// create a pool for drawn cards and our number generator
	drawnCards = new ArrayList();
	random = new Random();
	
	// shuffle the deck
	shuffle();
    }
    
    // returns the number of cards associated with this Deck
    public int getSize()
    {
	return cards.size() + drawnCards.size();
    }
    
    // draws the top card from the deck
    public Card draw()
    {
	// if the stack is empty, filil it using the drawn pile
	if(cards.isEmpty())
	    {
		shuffle();
	    }
	
	// pop the top Card, add it to the pile, then return it 
	Object card = cards.pop(); 
	drawnCards.add(card); 
	return (Card)card;              
    }
    
    // randomly shuffles the cards in this Deck
    public void shuffle()
    {
	// clear the stack
	while(!cards.isEmpty())
	    {
		drawnCards.add(cards.pop());
	    }
	
	// randomly draw cards from the drawn pile back onto the stack
	Object card = null;
	while(!drawnCards.isEmpty())
	    {
		card = drawnCards.remove
		    (Math.abs(random.nextInt())%drawnCards.size());
		cards.push(card);
	    }
    }
}    // Deck
And here's the tester class (CardTest.java):
import java.io.*;

// prints the String representation of a deck of cards to standard output
public class CardTest
{
    public static void main(String[] args) throws IOException
    {
	// create a deck of 52 cards
	Deck deck = new Deck(52); 
	
	// create a reader for entered keystrokes
	BufferedReader reader = new BufferedReader(new  
	    InputStreamReader(System.in));
	
	// display each card in the deck, allowing 
	// the user to pause between each one
	for(int i = 0; i < 52; i++)
	    {
		System.out.print("You drew the " + deck.draw());
		reader.readLine();
	    }
	
    }
} // CardTest
EXERCISES The next example uses inheritance to develop a concept in stages.

First, here's a basic scalar (Vector.java,) a unidimensional vector.

// a quick n' dirty class to represent a Vector object
public class Vector extends Object
{
    // the value of this Vector object
    protected int x;
    
    // creates a default Vector with a value of 0
    public Vector()
    {
	this(0);
    }
    
    // creates a Vector object with the sent value
    public Vector(int n)
    {
	setX(n);
    }
    
    // get/set access methods
    public final int getX()
    {
	return x;
    }
    
    public final void setX(int n)
    {
	x = n;
    }
    
    // translates the Vector by the sent value      
    public void translate(int dx)
    {
	x += dx;
    }
    
    // returns the String representation of this Vector
    public String toString() 
    {
	return "Vector [x=" + x + "]";
    } 
} // Vector

We use the scalar to define Vector2d.java (essentially a point in the plane).

// extends the Scalar class by adding a y component
public class Vector2d extends Vector
{
    // the added y value of this Vector2d object
    protected int y;
    
    // creates a default Vector2d with a value of (0,0)
    public Vector2d()
    {
	this(0, 0);
    }
    
    // creates a Vector2d object with the sent values
    public Vector2d(int m, int n)
    {
	setX(m);
	setY(n);
    }
    
    // get/set access methods for the y component
    public final int getY()
    {
	return y;
    }
    
    public final void setY(int n)
    {
	y = n;
    }
    
    // translates the Vector2d by the sent value        
    public void translate(int dx, int dy)
    {
	x += dx;
	y += dy;
    }
    
    // returns the String representation of this Vector2d
    public String toString() 
    {
	return "Vector2d [x=" + x + ",y=" + y + "]";
    } 
} // Vector2d
And here's Vector3d.java, a 3D vector (i.e., a point in space).

// extends the Vector2d class by adding a z component
public class Vector3d extends Vector2d
{
    // the added z value of this Vector3d object
    protected int z;
    
    // creates a default Vector3d with a value of (0,0,0)
    public Vector3d()
    {
	this(0, 0, 0);
    }
    
    // creates a Vector3d object with the sent values
    public Vector3d(int m, int n, int o)
    {
	setX(m);
	setY(n);
	setZ(o);
    }
    
    // get/set access methods for the z component
    public final int getZ()
    {
	return z;
    }
    
    public final void setZ(int n)
    {
	z = n;
    }
    
    // translates the Vector3d by the sent value        
    public void translate(int dx, int dy, int dz)
    {
	x += dx;
	y += dy;
	z += dz;
    }
    
    // returns the String representation of this Vector3d
    public String toString() 
    {
	return "Vector3d [x=" + x + ",y=" + y + ",z=" + z + "]";
    } 
} // Vector3d
Finally, here's the tester program:
public class VectorTest extends Object
{
    public static void main(String[] args) 
    {
	// print out the values of some Vector, Vector2d, and Vector3d objects
	System.out.println(new Vector());
	System.out.println(new Vector(5));
	System.out.println(new Vector2d());
	System.out.println(new Vector2d(4, 9));
	System.out.println(new Vector3d());
	System.out.println(new Vector3d(-12, 25, 2));
    } 
} // VectorTest
EXERCISES Here'a program that illustrates the use of abstract classes:
abstract class AbstractShape
{
    public abstract double area();
    public abstract double perimeter();
    
    static double totalArea(final AbstractShape[] shapes)
    {
	double total = 0.0;
	
	for(int i = 0; i < shapes.length; i++) 
	    {     total += shapes[i].area();
	    }
	return total;
    }
    
    static double totalPerimeter(final AbstractShape[] shapes)
    {
	double total = 0.0;
	
	for(int i = 0; i < shapes.length; i++) 
	    {     total += shapes[i].perimeter();
	    }
	return total;
    }
} // class AbstractShape

class Circle extends AbstractShape 
{
    private double radius;
    
    public Circle(double r) 
    {     radius = r;
    }
    public double area() 
    {     return Math.PI * radius * radius;
    }
    public double perimeter() 
    {     return (2.0 * Math.PI * radius);
    }
}

class Rectangle extends AbstractShape 
{
    private double width;
    private double height;
    
    public Rectangle(double w, double h)
    {     width  = w;
          height = h; 
    }
    public double area()
    {     return (width * height);
    }
    public double perimeter()
    {     return (2.0 * (width + height));
    }
}

public class ShapeTest 
{
    public static void main(String[] args) 
    {     
	AbstractShape[] myShapes = {
                                      new Rectangle(10.0, 20.0),
                                      new Circle(5.5),
                                      new Rectangle(0.1, 0.2)
		  }; 

	System.out.println(AbstractShape.totalArea(myShapes));

	System.out.println(AbstractShape.totalPerimeter(myShapes));

    }
} 
EXERCISES The next example creates objects and gives them unique identifiers (essentially VINs):
class IdObject
{
    // the next globally unique identifier for a newly created IdObject
    private static int uniqueId = 0;
    
    // the unique identifier for a single IdObject 
    private int id;
    
    // creates a new IdObject with the next unique integer identifier 
    public IdObject()
    { 
	// assign the next unique identifier to this object's id      
	id = uniqueId++;
    }
    
    // returns this object's unique identifier 
    public int getId()
    { 
	return id;
    }
    
    // returns the next available unique identifier for IdObjects 
    public static int getNextUniqueId()
    {
	return uniqueId;
    }
} // IdObject 

public class IdTest
{
    public static void main(String[] args)
    {
	// create 10 IdObjects, print their unique id's, then print the 
	// next available IdObject id
	
	IdObject[] objects = new IdObject[10];
	for(int i = 0; i < 10; i++)               
	    {     
		objects[i] = new IdObject();
		System.out.println("id = " + objects[i].getId());
	    }
	
	// now call the static getNextUniqueId method from the 
	// IdObject class to get the next available id
	System.out.println("Next id = " + IdObject.getNextUniqueId());
    }     
} // IdTest
EXERCISES Here's a program that illustrates the pervasiveness of interfaces in Java:
import java.util.*;

public class SortTest extends Object
{
    public static void main(String[] args) 
    {
	// create some Integer values
	Integer[] values = { new Integer(670), 
			     new Integer(90), 
			     new Integer(-23), 
			     new Integer(0),
			     new Integer(2),   
			     new Integer(659),
			     new Integer(1),   
			     new Integer(-40) };
	
	// sort the values
	Arrays.sort(values);
	
	// print the sorted array to the console
	for(int i = 0; i < values.length; i++)
	    {
		System.out.println(values[i]); 
	    }
    } 
} // SortTest
EXERCISES Here's an example of use of anonymous inner classes:
import java.util.*;

public class NameSortTest
{
    public static void main(String[] args)
    {          
	// create an array of Strings
	String[] strArray = 
	{ "Ward, Bill", "Osbourne, Ozzy", "Butlet, Geezer", "Iommi, Tony" };
	
	// print out the unsorted String array
	System.out.println("String array before sort:");
	for(int i = 0; i < strArray.length; i++)
	    {
		System.out.println(i + ": " + strArray[i]);
	    }
	
	Arrays.sort(strArray, new Comparator()
	    {
		public int compare(Object a, Object b)
		{
		    // cast a and b to String objects
		    String s1 = (String)a;
		    String s2 = (String)b;
		    
		    // since we're comparing by first name, parse the
		    // first name from the strings
		    s1 = s1.substring(s1.indexOf(",")+1);
		    s2 = s2.substring(s2.indexOf(",")+1);
		    
		    // trim off any leading or trailing whitespace 
		    s1 = s1.trim();
		    s2 = s2.trim();
		    
		    // let the String compareTo method compare the first names  
		    return s2.compareTo(s1);
		} // compare
	    } );
	
	// print out the newly sorted String array
	System.out.println("\nString array after sort:");
	for(int i = 0; i < strArray.length; i++)
	    {
		System.out.println(i + ": " + strArray[i]);
	    }
    } // main
} // NameSortTest
EXERCISES That should be enough welcome and warmups.


Last updated: Apr 3, 2002 by Adrian German for A201/A597/I210/A348/A548/T540/NC009