Friday, March 30, 2007

Interface VS Abstract class

Kapan pakai interface, dan kapan pakai abstract class?

Pertanyaan menarik ini muncul di milis jug-indonesia. Karena jawabannya cukup panjang, jadi saya copy-paste, sesuaikan sedikit, dan posting di blog.

First of all, ini pertanyaan advanced. Kapan pakai interface, dan kapan pakai abstract class itu cuma bisa dipahami dengan coding banyak-banyak (learning by doing), berpikir secara abstrak, dan banyak belajar desain aplikasi. Jadi jangan berkecil hati kalau Anda bingung setelah membaca artikel ini. Bukannya Anda tidak berbakat coding, tapi hanya kurang jam terbang saja.

Berikut jawaban saya.

Abstract class itu digunakan untuk mengimplementasikan pattern Template Method. Sedangkan interface digunakan (diantaranya) untuk mengimplementasikan pattern Observer.

Pakai interface bila satu class mau memiliki beberapa tipe data. Di Java, tipe data ditentukan oleh interface dan class. Mengacu pada buku Design Pattern, interface digunakan untuk menerapkan pattern Observer.

Contoh mudahnya seperti ini. Misalnya kita membuat aplikasi GUI. dan menggunakan komponen text (JTextArea). Komponen ini memiliki beberapa method untuk mengaktifkan event handling, beberapa diantaranya:

  • addMouseListener(MouseListener msl) : merespon gerakan mouse
  • addCaretListener(CaretListener cls) : merespon gerakan kursor

Kalau kita definsikan class seperti ini:

public class EventLog implements MouseListener, CaretListener {}

maka class EventLog bisa diumpankan pada kedua method di atas, karena class EventLog bertipe data EventLog, MouseListener, dan juga CaretListener.

Lalu, kapan kita menggunakan abstract class? Salah satunya apabila kita ingin membuat Template Method.

Kutipan dari Design Pattern GoF

By defining some of the steps of an algorithm using abstract operations, the template method fixes their ordering, but it lets Application and Document subclasses vary those steps to suit their needs.

Seperti kita ketahui, Template Method itu salah satu methodnya concrete dan (sebaiknya) final.

Contoh template method bisa dilihat di implementasi AbstractFormController di Spring Framework.

Untuk non-pengguna Spring, AbstractFormController itu mendefinisikan workflow pemrosesan HTML form. Method yang perlu diperhatikan di sini adalah method handleRequestInternal. Isi method ini kira2 seperti ini (dimodifikasi agar mudah dimengerti):

protected void handleRequestInternal() {
bindDataDariForm();
setelahBindSebelumValidasi();
validasiData();
setelahValidasi();
processFormSubmission();
}

Seperti kita lihat di atas, method ini memanggil beberapa method lain secara berurutan. Urutan ini penting, karena kita tidak mau validasi dipanggil setelah form diproses. Apa gunanya validasi kalau pemrosesan sudah selesai?

Class AbstractFormController ini punya abstract method, yaitu:

public abstract void processFormSubmission();

Kenapa dibuat abstract? Karena pada saat menulis kode tersebut, Rod Johnson tidak tahu apa yang kita ingin lakukan pada saat form diproses. Ada yang mau simpan ke database, ada yang mau kirim email, dan berbagai kegiatan lain yang tidak terbayangkan sebelumnya. Oleh karena itu, method ini dibuat abstract, sehingga kita harus membuat implementasinya (override)

Nah, kita sebagai end-user, biasanya hanya perlu mengimplement method processFormSubmission tersebut. Method lainnya hanya dioverride apabila perlu. Misalnya kita ingin pakai logika validasi sendiri, atau ada pemrosesan khusus setelah validasi.

Teknik Template Method ini tidak bisa diimplement dengan interface, karena harus ada method concrete handleRequestInternal yang berfungsi untuk mendefinsikan workflow.

Demikian, mudah-mudahan bisa dimengerti.

Sunday, March 18, 2007

Advance Swing

This tutorial covers more advanced
Java Swing topics such as dropdown menus,
popup menus, toolbars, tooltips, specialized containers, layered panes,
split panes, tabbed panes, tables, trees and file choosers. Inner class
event listener material using inner classes is also included.




Advanced Event Listeners


One difficulty with the basic event listening

technique (ie event sharing) previously demonstrated is that it becomes
awkward to program for many buttons and widgets. Extended if statements or
switch constructs can make code hard to maintain. There is a better way!


Inner classes (ie nested) allow routines to be written for each
specific object. For example instead of using addActionListener(this)
for several buttons you can have each button call its own inner class such as:


import java.awt.*;import java.awt.event.*;import javax.swing.*;
public class SomeGUI extends JFrame
{
JButton run = new JButton("Run the Utility");
JButton exit = new JButton("Exit After Save");
JPanel buttons = new JPanel(new GridLayout(4,1,2,2));
SomeGUI() // the constructor
{
super("Event Listener Demo"); setBounds(100,100,250,150);
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
buttons.add(run); buttons.add(exit);
this.getContentPane().add("Center",buttons);
exit.addActionListener(new ExitHandler()); setVisible(true);
}
// add inner class event handler for each button here
class ExitHandler implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
System.exit(0);
}
}
public static void main(String[] args) {new SomeGUI();}
}

NOTE: The implements clause is now placed in
each inner class header and not in the main class header.
Also the listener registration is of a specific Listener_class

object, not the generic this.


Anonymous inner classes have no name (hence no name conflict)
and are used when only one instance of the class is required. They also
do not have constructors. Anonymous inner classes are most often found
in event listeners. A simple example for the exit button is:


exit.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
System.exit(0);
}
});

Yet another strategy (using outer classes) allows isolation of the event
listeners to external files but is more complex to code because of inherent
information hiding.


Consult the appendix for a list of
other programmable events. As event classes are interfaces, all

methods within that event must be implemented. Adapter classes
provide default do-nothing methods which you can chose to override. Here
is a short example using the WindowAdapter class to avoid coding all seven
window events.


import java.awt.*;import java.awt.event.*;
class Listener2 extends Frame
{
Listener2()
{
setBounds(100,100,200,200); setVisible(true);
addWindowListener(new WindowAdapter()
{
public void windowclosing (WindowEvent e)
{ System.exit(0); }
});
}
public static void main (String[] args) {new Listener2();}
}


Menu Bars and Popups


Dropdown/pullout menu bars are menus similar to those that appear
across the top of most Windows programs. The menu bars are constructed from
the JMenuBar class. Menus (aka bar items) are constructed from the
JMenu class and menu items from the JMenuItem class.
Item separators can either be added to a menu with addSeparator()

or inserted with insertSeparator(posn). Menu items can be disabled
or grayed out with the setEnabled(false) method and tested with the
isEnabled() method. Menu items can have a hotkey shortcut
added by using a setMnemonic(char) method. Accelerator keys
are added with the setAccelerator() method. The menubar is added to
the main frame by using this.setJMenuBar(obj).



MyMenu.java demonstrates many of the features of the menu classes
including mnemonics, accelerators keyed to platform, checkbox &
radiobutton items and icons. Download the
jp6grabbag.zip
package


Popup menus are revealed by some user action and look similar
to a dialog box.


MyPop.java demonstrates features of the popup menu classes
including specialized listeners. Download the

jp6grabbag.zip
package



ToolBars and ToolTips


Dockable toolbars can be constructed from the JToolBar
class. JToolBar(SwingConstants.VERTICAL) overrides the default
orientation. The add() method adds components which are often
icons. Toolbars are always fully exposed.



Tooltips give popup text for any hovered object such as
buttons and toolbar components. The setToolTipText() method
is used to associate informational text with the object or icon.


MyToolBar.java demonstrates features of the toolbar class
including action classes. Download the
jp6grabbag.zip
package



Specialty Frames and Panes


Layered panes allow components such as buttons to be overlapped
or layered.


import java.awt.*; import java.awt.event.*; import javax.swing.*;
public class Frame3 extends JFrame
{
public Frame3() // constructor method for the class
{
super("Simple Layers Demo"); setBounds(100,100,300,200);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLayeredPane lp = getLayeredPane(); // inherit the layered pane
JButton top = new JButton();
top.setBackground(Color.white);
top.setBounds(20,20,50,50);
JButton mid = new JButton();
mid.setBackground(Color.gray);
mid.setBounds(40,40,50,50);
JButton bot = new JButton();
bot.setBackground(Color.black);
bot.setBounds(60,60,50,50);
lp.add(mid,new Integer(2));
lp.add(top,new Integer(3));
lp.add(bot,new Integer(1));
setVisible(true);
}
public static void main(String[] args) {new Frame3();}
}

Split panes allow you to place two components side by side
in a single pane. The divider can be adjusted by the user. It can also
split the pane horizontally. A simple example of a split pane is:


import javax.swing.*; import java.awt.*; import java.awt.event.*;
class MySplit extends JFrame
{
static String sometext = "This is a simple text string that is long enough "+
"to wrap over a few lines in he simple demo that we have just built. We "+
"will put two Text areas side by side in a split pane";
public MySplit()
{
super("Simple JSplitPane Frame"); setSize(450,200);
JTextArea jt1 = new JTextArea(sometext);
JTextArea jt2 = new JTextArea(sometext);
jt1.setLineWrap(true); jt1.setMinimumSize(new Dimension(150,150));
jt2.setLineWrap(true); jt2.setMinimumSize(new Dimension(150,150));
jt1.setPreferredSize(new Dimension(250,200));
JSplitPane sp = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,jt1,jt2);
getContentPane().add(sp, BorderLayout.CENTER);
setDefaultCloseOperation(EXIT_ON_CLOSE); setVisible(true);
}
public static void main (String args[]) {new MySplit();}
}

Tabbed panes allow a multilayered pane with tabs for the
user to access the layer he wants. Each tab contains a single component.
A simple example of a tabbed pane is:



import javax.swing.*; import java.util.*;
import java.awt.*; import java.awt.event.*;
class MyTab extends JFrame
{
JTabbedPane jtp;
public MyTab()
{
super("JTabbedPane"); setSize(200,200);
Container contents = getContentPane();
jtp = new JTabbedPane();
jtp.addTab("Tab1", new JLabel("This is Tab One"));
jtp.addTab("Tab2", new JButton("This is Tab Two"));
jtp.addTab("Tab3", new JCheckBox("This is Tab Three"));
contents.add(jtp);
setDefaultCloseOperation(EXIT_ON_CLOSE); setVisible(true);
}
public static void main (String args[]) {new MyTab();}
}


Tables


Tables represent data in a row/column two dimensional grid
format. The simplest constructor is of the form JTable(data,headers)
where data is a two dimension string and headers is a one dimension string.
SimpleTable is a small demo.
Download the jp6grabbag.zip package



Hierarchical Trees


Trees allow visualization, traversal and manipulation of
hierarchical information (ie. parent-children) much easier. Trees consist
of nodes. Common examples of trees are directories, organizational
charts, and family trees.


In Java the JTree(var) constructor is used to create trees.
The variable parameter can be one of TreeNode, TreeModel, Object, Vector,
or Hashtable class. A simple example is ObjectTree which uses a
hashtable to hold the actual tree.
Download the jp6grabbag.zip package



File Choosers


The JFileChooser class is part of the javax.swing.filechooser
package. It allows browsing through a file system and selecting appropriate
files. The JFileChooser(stringVar) constructor can be used to set
the starting browsepoint (currentDirectory is common). An external
FileFilter extension or a FileNameExtensionFilter
(depending on Java version) can be added using the
addChoosableFileFilter() method to limit the scope of the selection.
The following code demonstrates opening a chooser to get a file or directory
names:



Warning: Use getCanonicalPath() to retain the
directory path information for file access! This method
requires Exception handling. Use
getName() only when the string will be used for simple display purposes.


import java.awt.*;import java.awt.event.*;
import java.io.*; import javax.swing.*;
public class MyBrowser extends JFrame
{
String curDir; JLabel statusbar;
public MyBrowser()
{
super("File Chooser Test Frame"); setSize(350,200);
setDefaultCloseOperation(EXIT_ON_CLOSE);
curDir = System.getProperty("user.dir") + File.separator;
statusbar = new JLabel("Output of your button choice goes here!");
Container c = getContentPane(); c.setLayout(new FlowLayout());
JButton openButton = new JButton("Open");
JButton dirButton = new JButton("Pick Dir");
// add the open FILE chooser
openButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
JFileChooser chooser = new JFileChooser(curDir);
chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
chooser.setMultiSelectionEnabled(true);
//Java 1.6 can use FileNameExtensionFilter class
// FileFilter filter=new FileNameExtensionFilter("HTML file","htm","html");
// chooser.addChoosableFileFilter(filter);
//Prior versions must use external extension of FileFilter class (ie ExtFilter)
//ExtFilter requires separate compile to enable choosable selection
String[] html = new String[] {"htm","html","xhtml"};
chooser.addChoosableFileFilter(new ExtFilter(html,
"HTML file (*.htm, *.html)"));
int option = chooser.showOpenDialog(MyBrowser.this);
if (option == JFileChooser.APPROVE_OPTION)
{
File[] sf = chooser.getSelectedFiles();
String filelist = "nothing";
try
{
if (sf.length > 0) filelist = sf[0].getCanonicalPath();
for (int i = 1; i < sf.length; i++)
{filelist += ", " + sf[i].getCanonicalPath();}
}
catch (IOException evt) {System.out.println("Exception: "+evt);}
statusbar.setText("Your choices: " + filelist);
}
else {statusbar.setText("You cancelled!");}
}
});
// add the open DIRECTORY chooser
dirButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent ae)
{
JFileChooser chooser = new JFileChooser(curDir);
chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
chooser.setMultiSelectionEnabled(false);
int option = chooser.showOpenDialog(MyBrowser.this);
if (option == JFileChooser.APPROVE_OPTION)
{
File[] sf = chooser.getSelectedFiles();
String filelist = "nothing";
try
{
if (sf.length > 0) filelist = sf[0].getCanonicalPath();
for (int i = 1; i < sf.length; i++)
{filelist += ", " + sf[i].getCanonicalPath();}
}
catch (IOException evt) {System.out.println("Exception: "+evt);}
statusbar.setText("You chose " + filelist);
}
else {statusbar.setText("You cancelled!");}
}
});
c.add(openButton); c.add(dirButton); c.add(statusbar); setVisible(true);
}
public static void main(String[] args) {new MyBrowser();}
}


Here is my version of the ExtFilter class. It must be separately
compiled if choosable extension selection is enabled for Java versions prior
to 1.6 The class receives rither an extension or list of extensions and a
description of the extension(s).


import java.io.File; import javax.swing.filechooser.*;
public class ExtFilter extends FileFilter
{
String[] extensions; String description;
public ExtFilter(String ext) {this (new String[] {ext},null);}

public ExtFilter(String[] exts, String descr)
{
extensions = new String[exts.length];
for (int i=exts.length-1;i>=0;i--){extensions[i]=exts[i].toLowerCase();}
description=(descr==null?exts[0]+" files":descr);
}
public boolean accept(File f)
{
if (f.isDirectory()) {return true;}
String name = f.getName().toLowerCase();
for (int i=extensions.length-1;i>=0;i--)
{if (name.endsWith(extensions[i])) {return true;} }
return false;
}
public String getDescription() {return description;}
}



Exceptions and Threads

Exception handling is a method of trapping or coping with anticipated errors (system, data entry or calculation) and handling or dealing with them in a graceful manner. The Exception class of objects offers a rich group of subclasses to trap specific errors and recover from them.

A thread is the flow of execution of a single set of program statements. Multithreading consists of multiple sets of statements which can be run in parallel. With a single processor only one thread can run at a time but strategies are used to make it appear as if the threads are running simultaneously. Depending on the operating system, either timeslicing or interrupt methods will move the processing from one thread to the next.

What Exceptions Are

Exceptions are objects that describe any error caused by an external resource not being available or an internal processing problem. They are passed to exception handlers written by the programmer to enable graceful recovery. If the handler has not been written, the program will terminate with a display of the Exception class. There are many exception classes such as IOException and NumberFormatException.

Exception Handling

Java uses the try - catch - finally syntax to test (ie. try) a section of code and if an error occurs in that region, to trap (ie. catch) the error. Any number of catches can be set up for various exception types. The finally keyword can be used to provide a block of code that is performed regardless of whether an exception is signaled or not. The syntax is:

try

{

// tested statement(s);

}

catch (ExceptionName e1)

{

// trap handler statement(s);

}

catch (ExceptionName e2) // any number of catch statements

{

// display exception to screen

System.out.println("Exception: " + e2);

}

finally

{

// always executed block

}

throws and throw Keywords

throws is used to pass a possible exception up the stack (processing chain). The Java compiler is aware of how some methods may cause specific exceptions and it forces you to deal with these immediately. N.B.: If you choose not to write an exception handler then use the throws xxxException clause on the surrounding method to abdicate responsibility. For example using System.input() will give a compile error for IOException. Add the throws clause to the method to pass the error to next level (or else write your own catch/try handler).

The throw keyword (note the singular form) is used to force an exception. It can also pass a custom message to your exception handling module. For example:

throw new FileNotFoundException("Could not find beatles.txt");

Effective Hierarchy

The exception classes are arranged in a hierarchy. Handlers (or catches) for specific exceptions should always be written prior to the generic handler. For example since FileNotFoundException is a child of IOException, a catch for FileNotFoundException should occur before the one for IOException. The latter handler will catch those exceptions that are missed by individual child handlers. And a generic handler for Exception would cover any missing situation.

FileInputStream fis=null;  // declare in outer block

try

{

fis = new FileInputStream (new File (args[0])); // uses cmd line

int ch;

while (ch = fis.read() != -1)

{System.out.print ((char) ch);}

fis.close();

System.out.println("");

}

catch (FileNotFoundException e)

{

System.out.println("File not found!");

try

{

fis.close();

}

catch (IOException ioe) {} // disregard close failure

}

catch (IOException e)

{

try

{

fis.close();

}

catch (IOException ioe) {} // disregard close failure

System.out.println("Unable to read file!");

}

Assertions

Many modern programming languages let you test assumptions with an assertion construct. Java uses assert to test the validity of a logic statement such as assert a. If the assertion is not true, an AssertionError exception is thrown. assert a will attach a custom error message to the exception for display purposes. Common uses are to check for null strings passed in as method parameters and to prevent the possibilitiy of division by zero.

NOTE: To enable asssertion testing at runtime you must use a -ea switch on the command line. If using an IDE you must RTFM.

Reflection

Reflection is the capability for one object to inspect another object's characteristics. It uses classes provided by the java.lang.reflect package. These classes are Field, Method, Constructor, Array and Modifier.

A useful example of reflection is provided by SeeMethods.java (found in http://home.cogeco.ca/~ve3ll/bin2/jp7collections.zip). Compile with javac SeeMethods.java and then run it with java SeeMethods classname This will give a display of all methods in classname as well as their modifiers, return type and parameters.


Using The Thread Class

The Thread Class allows multitasking (ie running several tasks at the same time) by instantiating (ie creating) many threaded objects, each with their own run time characteristics. One way is to extend the Thread class and override the run() method such as:

class HelloThread extends Thread

{

public void run()

{

for int x=0;x<100; style=""> System.out.print(" Hello ");

}

}

However if you need to inherit from another class as well, you can implement a Runnable interface instead.

class HelloThread implements Runnable

{

Thread t = new Thread(this);

t.start();

public void run()

{

for int x=0;x<100; style=""> System.out.print(" Hello ");

}

}

Thread object methods are used on instantiated thread objects to control the thread appropriately. These methods include run(), start(), sleep(longInt), join(), isAlive(), currentThread(), getName(), setName(string), getPriority() and setPriority(int).

Some older methods such as stop(), suspend() and resume() have been deprecated as they sometimes caused system instability or hangup! A better way of stopping a thread is making the run method into a while loop based on a logical that can be set to false as in:

public void run() {

while (okToRun==true) {

// do the run time stuff here

}

}

Inner classes are used to set up multiple threads in a utility.

Assigning Priority

Priority is ranking. Some threads can either run for a longer timeslice or run more often (depending on the operating system). Peers (or equals) get the same time/number of runs. Priority is set from MIN_PRIORITY (currently 1) to MAX_PRIORITY (currently 10) using the setPriority(int) method. NORM_PRIORITY is the midrange value (currently 5). These constants are defined in the Thread class.

Example: Digital Clock

A good example of using threads for animation is the applet .Clock.zip. A ready-to-run version is found in http://home.cogeco.ca/~ve3ll/bin2/jp7collections.zip. The output could also be displayed in the browser's status line by using the showStatus(string_msg) method.

/**

* The Clock class demonstrates animation with threads

*/

import java.awt.*; import java.applet.*; import java.util.*;



public class clock extends Applet implements Runnable

{

Font f = new Font("TimesRoman",Font.BOLD,24);

Date d; Thread runner;



public void init()

{resize(300,100);}



public void paint(Graphics g)

{g.setFont(f);g.drawString(d.toString(),10,50);}



public void start()

{

while (runner == null)

{

runner = new Thread(this); runner.start();

}

}



public void run()

{

while (true)

{

d = new Date(); repaint();

try {Thread.sleep(1000);}

catch(InterruptedException e){};

}

}

}

Example: Splash Screen

Splash screens are opening screens that many commercial programs use to 'spiff' up their appearance. Once a splash has run for a set time or when user interrupted it is tossed away and the actual application appears. Program ending credits can be rolled in the same way but done at application close time instead.

ExtendThreadClass.java (found in http://home.cogeco.ca/~ve3ll/bin2/jp7collections.zip) is an extended java class that can be easily adapted into a splash screen. SimpleThread.java (found in http://home.cogeco.ca/~ve3ll/bin2/jp7collections.zip is an implemented class that also illustrates how a user interrupt can force a fast finish to the splash.

Example: Animation

Animation is the appearance of life or movement in an object. It is achieved by redrawing screens with objects shifted slightly. Realistic movement is achieved by appropriate choices of shift and refresh rate.

AniMain.java (found in http://home.cogeco.ca/~ve3ll/bin2/jp7collections.zip) is a simple Java game that involves animation. Read the source code for techniques on using threads to make objects appear to have life by rapid screen redraws.

File IO

Input/output operations route data from the keyboard, files or programs into your program and from there to the screen, printer, files or other programs. For simple tasks such as dumping your output to a file or printer or using a text file as an input script simple redirection provided by the operating system is all that is required. Our previous tutorials have used System.in and System.out objects to read and write from the standard input and output streams.

For more complex IO activities, modern languages use the concept of streams. Java uses file streams, data streams, pipe streams and object streams to manipulate I/O. For these you must access the io class library with the instruction import java.io.*

File Management

File management is the manner in which files are monitored and controlled for standard I/O access. The File class provides a constructor to create a file handle. This file handle is then used by various file class methods to access the properties of a specific file or by file stream constructors to open files. The File class also provides appropriate platform dependent directory and file separator symbol (slash or backslash) using either File.separator or File.separatorChar. Simple file constructors either use hardcoded names or pass a value from the parameter line such as:

File hard = new File(File.separator + "sample.dat"); // in root dir
File soft = new File(args[0]); // entered as part of command line

Accessor methods: getAbsolutePath(), getCanonicalPath(), getName(), getPath(), getParent(), lastModified(), length(), list() {returns array of String}, listFiles() {returns array of File objects}.

Mutator methods: delete(), deleteOnExit(),mkdir(), mkdirs(), renameTo(), setLastModified(), setReadOnly().

Boolean methods: canRead(), canWrite(), compareTo(), exists(), isAbsolute(), isDirectory(), isFile(), isHidden().

Here is a very useful routine to establish the current directory path:

public class CurrentDir {
public static void main (String args[]) {
String dir="user.dir"; // set to current directory
try {dir=new File(System.getProperty(dir)).getCanonicalPath();}
catch (IOException e1) { /*handler required but null */ }
System.out.println ("Current dir : " + dir);
}
}

To limit what is returned by the list() method, apply a filter using the FilenameFilter interface. accept() is the only method allowed. A program showing the use of Filefilter is:

class OnlyExt implements FilenameFilter
{
String ext;
public OnlyExt(String ext)
{ this.ext = "." + ext; }
public boolean accept(File dir, String name)
{ return name.endsWith(ext); }
}
class DirListOnly // *.htm for example
{
public static void main(String args[])
{
String dirname="./website"; // select directory
File f1 = new File(dirname);
FilenameFilter only = new OnlyExt("htm"); // and ext
String files[] = f1.list(only); // array of files
for (int i=0; i

Note: More sophisticated GUI techniques for selecting files include the Swing FileChooser class and its awt cousin FileDialog. These classes also include file filters and checks for existence and the ability to access the data.

File Streams

File streams are primitive streams whose sources or destinations are files. Both byte [8-bit] (FileInputStream / FileOutputStream) and character [16-bit] (FileReader / FileWriter) quantities can be used. Some sample constructors are:

FilenInputStream(fileObj)                 FileReader(fileObj)
FileInputStream(FilePath[,append_flag]) FileReader(filePath[,append_flag])
FileOutputStream(fileObj) FileWriter(fileObj)
FileOutputStream(FilePath[,append_flag]) FileWriter(filePath[,append_flag])

Note 1: Use character streams for new code! This allows Unicode material to be processed correctly.

Note 2: The read() method returns an integer even when character streams are used. Java still has some quirks to keep you thinking!!

copybyte.java is a working file IO system that uses primitive file streams to read and copy bytes to a new file. You can use copybyte as a start point for other utilities by placing code between the read() and write() methods. However there are more efficient ways of handling most types of data. File streams should be wrapped and buffered in data streams.

Data Streams

Data streams are streams whose sources and destinations are other streams. They are known as wrappers because they wrap the primitive file stream object mechanism inside a more powerful one. Data streams are buffered so that more than a single 8/16 bit quantity is processed at a time. The basic buffered streams are BufferedInputStream(), BufferedOutputStream(), BufferedReader() and BufferedWriter().

Java does not provide an EOF() method as other languages do! read() returns an integer -1 when an EOF occurs and readLine() returns null. But a better technique is to use an exception handler to catch the EOFException and handle it. Check the Exceptions tutorial. You may also want to close the file if it was sequential access.

copyline.java is a working io system that uses buffered data streams to read and copy lines to a new file. Many utilities rely on text files which are often best handled one line at a time. You can use this sample as a start point for your own utility between the readLine() and write() methods.

DataInputStream() and DataOutputStream() streams can also be used to read/write one primitive quantity at a time. Some of the useful methods are: read(), readBoolean(), readByte(), readDouble(), readFloat(), readInt(), readLong(), readShort(), readLine(), write(), etc.

Tokens (or words) are strings broken at whitespace. Adding the StringTokenizer class makes some utilities more efficient because they can work with individual tokens rather than whole lines of text (ie. the line is already parsed for analysis). The StreamTokenizer class can also be used to read directly from a file stream! copytoken.java is a working file io system that uses a token stream to read and copy tokens to a new file.
Note: Whitespace is minimized which makes this format great for compressing HTML source files into a server copy. You can also use copytoken as a start point and add your own utility between the read and write operations. One easy project to start with is wc (the Unix word count utility).

Random Access Files

Random access files allow files to be accessed at a specific point in the file. They can also be opened in read/write mode which allows updating of a current file. The constructor is RandomAccessFile(File fileObject, String accessMethod) where the access method is either "r" or "rw". The seek(long position) method moves the file position pointer. It is incremented automatically on a write. The getFilePointer() method returns the current file position pointer. The file size can be adjusted with setLength(). Normal i/o methods are used for access.

copyrandom.java is a working random access file io system that uses bit streams to read and copy binary data to a new file. Note that it illustrates file creation but does not demonstrate either the ability to access at specific points in the file or the update a single file strengths of random access methods.

mirror.java shows a very simple use of the seek() method. The source file is read backwards and each byte written to a new file. This is one of the simplest forms of encryption offered.

RandomAccess.java is a more complete example that uses user input to alter file contents. Since it extends GenericApplication, that file must be compiled first. Once both are compiled, test with java RandomAccess xxx where xxx is the filename.

To fully implement a random access io system, you must structure your own record format and then use this structure to determine record size for the seek method. You must also provide your own indexing method based on one or more fields of the record. The java.io library provides only the primitive functions necessary. At this point you may want to seek out a random access toolbox provided by another implementer!!

Project: Text File IO Class

This project will test your knowledge of basic file IO as well as how to encapsulate an object. The task is to make a TextIO object that has methods to open data streams and to read and write text files on a line by line basis. The required GUI will be added as part of a case study. To have the program do something write a worker class that removes comment lines from a file. This will require the indexOf() and substring() methods from the String class

A simple enhancement that makes use of this TextIO class is a pager utility which takes a file and makes single page files of every 55 line group. This overcomes the problem of the java \f formfeed not working with many printers. Possible command line switches are:

  • /lines=n sets the # of lines in each file [default is 55]
  • /head=n sets the # of lines used as heading [default is 0]
  • /title="string" sets the first line title [default of none]

Project: Archive Packaging

This project will extend the use of the TextIO class you just constructed as well as begin to replicate a old unix utility called archive. The task is to make an archive object that \has methods to both merge text files into a block and to extract them.

The first version uses a trivial token file marker (*** ) and extracts to named or numbered files. A loop is needed to continue the extracting process. The command line syntax is archive.java filename.

The first project enhancement is to incorporate switches for pack/unpack/update, etc and to add required functionality.

A final extension would be to use a whitelist to add files or deblock files. This project can keep one busy for a week at least!

Batch File Shell

Many utilitities can benefit from a shell code routine that allows running over a complete directory or a file subset (batch mode).

touch.java updates the last_modified field of all files in the current directory to the current date. This overcomes a flaw in XP that sometimes deletes older files without informing the user. Programmers can also use touch to make sure libraries are recompiled with the latest version of the compiler.

longest.java [ext] uses a command line approach and a FilenameFilter to execute on all files with a given extension. The batch operation wraps around a method that identifies the longest line in each file.

Command line wildcard file constructs are automatically expanded at runtime and passed to programs as command line arguments. Careful attention must be given here! wildcard.java shows how to handle command line wildcard expansion.

Ongoing Projects

WordCount2.java adds basic file IO to our previous project in word counting. Reuse the WordCount class and add the text io class to the workspace class. Use fixed or argument filenames for now. The required GUI will be added as part of a case study.

Prep2.java adds basic file IO to our previous project in cipher text preparation. Reuse the Prep class and add the text io class to the workspace class. Use fixed or argument filenames for now. The required GUI will be added as part of a case study.

TagScan2.java adds basic file IO to our previous project in HTML analysis. Reuse the TagScan class and add the text io class to the workspace class. Use fixed or argument filenames for now. The required GUI will be added as part of a case study.

Class Libraries

To help programmers be more productive, Java includes predefined class packages (aka Java class libraries) as part of the installation. Some specific package/libraries are: applets java.applet, language extensions java.lang, utilities java.util, formatters java.text, io java.io, GUI java.awt and javax.swing, network services java.net, precision math java.math, database management java.sql, security java.security.

Note: Some programmers find that using an interactive development environment (IDE) such as NetBeans, JCreator or JBuilder to be very helpful in accessing and using the many extended features that these class libraries provide. Others stay with a basic text editor and develop a more complete understanding of the libraries. It is your call but I recommend a basic text editor for beginning programmers.

Note: Unless another library is indicated the following classes are contained in the java.lang package.

Packages

One of the goals of Java is code reusability. The library keeping function for code reuse is enabled through the use of packages of precompiled classes that can be imported into other projects. This allows developers to distribute their work as toolkits without distributing the source code. Programmers can use these classes as easily as using the classes distributed as part of the developers kit.

All that is required to package a group of classes for reuse in other projects or for distribution is to include the package directive in your source file prior to any executable code. An example might be: package toolkit; where toolkit refers to the folder that the class(es) will be stored in. Sublevels of folder are supported through dot notation. The convention for package names which ensures uniqueness is to reverse the order of your domain name. For example ACME.com would set up its toolkit as com.acme.toolkit.

The import directive is used to incorporate packaged classes within a new project. It is placed prior to any executable code (but after any package directive if there is one). For the above examples of packages, the corresponding import statements would be

import toolkit.*; import com.acme.toolkit.*;

The package location's root is determined by an operating system environment variable called classpath. It can have multiple entries which are used in sequence as search paths. The first matching entry is used. As an example of a WindowsXP classpath here is mine:

classpath=.;C:\Program Files\Java\jdk1.5.0_10\bin;

This says to first look in the current directory and if a class file isn't there look inside the bin folder of the installed distribution package.

Type Wrappers

Wrappers are classes used to enclose a simple datatype or a primitive object into an object. This is sometimes necessary because:

  • Simple datatypes are not part of the object hierarchy.
  • Simple datatypes are passed by value and not by reference.
  • Two methods can't refer to the same instance of a simple type.
  • Some classes can only use members of another class and not a simple type.
  • The wrapped object lacks advanced methods needed for object manipulation

The Number class wrapper has subclasses of Byte, Short, Integer, Long, Double and Float. Each of these subclasses have methods for converting from and to strings such as: parseInt(str[, radix]), valueOf(str[, radix]), and toString(value).

The Boolean class wrapper allows passing Boolean values (true and false) by reference.

The Character class wrapper has many methods available, some of which are:

  • isLowerCase(char c)
  • isUpperCase(char c)
  • isDigit(char c)
  • isLetter(char c)
  • isLetterOrDigit(char c)
  • isWhitespace(char c)
  • toLowerCase(char c)
  • toUpperCase(char c)
  • compareTo(String g)

Note: Java 1.5 has introduced automatic type conversion (casting) between primitives and wrapper objects. For example the following are equivalent:

Integer num = 17;
Integer num = new Integer(17);

The System Class

The System class provides access to the native operating system's environment through the use of static methods. As an example System.currentTimeMillis() retrieves the system clock setting (as a long, in milliseconds counted from January 1, 1970). Some of the available methods are:

  • currentTime()
  • freeMemory()
  • totalMemory()
  • exit(int status)
  • exec(String cmd)
  • execin(String cmd)
  • getenv(String var)
  • getCWD()
  • getOSName()
  • arraycopy(src[], srcpos, dest[], destpos, len)

Another method called System.getProperty("property_name") allows access to the following system properties:

  • file.separator
  • line.separator
  • path.separator
  • os.arch
  • os.name
  • os.version
  • user.dir
  • user.home
  • user.name
  • java.class.path
  • java.class.version
  • java.home
  • java.vendor
  • java.vendor.url
  • java.version
  • java.vm.name
  • java.vm.vendor
  • java.vm.version

NOTE: Many System class methods throw a SecurityException error for safety reasons.

The System class also provides very basic io streams for console read, write and error operations. System.in.read() reads a keystroke and returns an integer value. System.out.println(string) displays a string to the current output device.

Note: There are much better ways for user interaction. You can refer to io streams for methods of reading more than a keystroke at a time or refer to GUI stuff for visual interfaces using AWT and Swing objects.

The Math Class

The Math class provides the important mathematical constants E and PI which are of type double.

The Math class also provides many useful math functions as methods.

GroupMethods
Transcendental acos(x), asin(x), atan(x), atan2(x,y), cos(x), sin(x), tan(x)
Exponential exp(x), log(x), pow(x,y), sqrt(x)
Rounding abs(x), ceil(x), floor(x), max(x,y), min(x,y), rint(x), round(x)
Miscellaneous IEEEremainder(x,y), random(), toDegrees(x), toRadians(x)

Note: To generate a random integer between 1 and x you can use the following.

intRnd = (int) (Math.random() * x) + 1;

The DecimalFormat Class [java.text library]

Applications that require highly customized number formatting and parsing may create custom DecimalFormat class objects by passing a suitable pattern to the DecimalFormat() constructor method. The applyPattern() method can be used to change this pattern. A DecimalFormatSymbols object can be optionally specified when creating a DecimalFormat object. If one is not specified, a DecimalFormatSymbols object suitable for the default locale is used. Decimal format patterns consists of a string of characters from the following table. For example: "$#,##0.00;($#,##0.00)"

CharInterpretation
0A digit // leading zeros show as 0
#A digit // leading zeros show as absent
.The locale-specific decimal separator
,The locale-specific grouping separator (comma)
-The locale-specific negative prefix
%Shows value as a percentage
;Separates a positive number format (on left) from
an optional negative number format (on right)
'Escapes a reserved character so it appears literally in the output

Here is an example of how DecimalFormat can be used:

import java.text.*;
public class test
{
public static void main (String args[])
{
int numb = 3; String rptNumb;
DecimalFormat df = new DecimalFormat("000");
rptNumb = df.format(numb); System.out.println(rptNumb+"\n");
}
}

The DecimalFormat class methods are as follows:

GroupMethods
Constructor DecimalFormat (), DecimalFormat(pattern), DecimalFormat(pattern,symbols)
Accessor getDecimalFormatSymbols (), getGroupingSize(), getMultiplier(), getNegativePrefix(),,getNegativeSuffix(), getPositivePrefix(), getPositiveSuffix()
Mutator setDecimalFormatSymbols(newSymbols), setDecimalSeparatorAlwaysShown(newValue), setGroupingSize(newValue), setMaximumFractionDigits(newValue), setMaximumIntegerDigits(newValue), setMinimumFractionDigits(newValue), setMinimumIntegerDigits(newValue), setMultiplier(newValue), setNegativePrefix(newValue), setNegativeSuffix(newValue), setPositivePrefix(newValue), setPositiveSuffix(newValue)
Boolean equals(obj), isDecimalSeparatorAlwaysShown()
Instance applyLocalizedPattern(pattern), applyPattern(pattern), String toLocalizedPattern(), String toPattern(),

The Calendar Class [java.util library]

The Calendar class provides a set of methods for formatting dates. getInstance() returns the current date/time as a Calendar object. get(param) returns the specific parameter as a string object. Param can be YEAR, MONTH, DAY_OF_MONTH etc.

GroupMethods
Constructor none
Accessor get(), getAvailableLocales, GetInstance(), getTimeZone()
Mutator set(), setTime(), setTimeZone()
Boolean equals(), isSet()

The Date Class [java.util library]

The Date class provides a standard format for any member of the class.The Date class methods are as follows:

GroupMethods
Constructor Date()
Accessor long getTime()
Mutator String Date.toString()
Boolean before(Date when), after(Date when), equals(Date when)

The Date Format Class [java.text library]

The abstract class DateFormat and its concrete subclass SimpleDateFormat provides the ability to format and parse dates and times. The constructor normally takes a formatting string made from the following symbols:

CharMeaning
aAM or PM
dDay of month
hHour (1-12)
kHour (1-24)
mMinute
sSecond
wWeek of year
yYear
zTimezone
:Separator
CharMeaning
DDay of year
EDay of week
FDay of week in month
GEra (AD or BC)
HHour in Day (0-23)
KHour in Day (0-11)
MMonth
SMillisecond
WWeek of month
/Escape character

Here is an example of how SimpleDateFormat can be used:

import java.text.*; import java.util.*;
public class test
{
public static void main (String args[])
{
Date date = new Date(); String rptDate;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy MMM dd @ hh:mm");
rptDate = sdf.format(date); System.out.println(rptDate+"\n");
}
}

Project: Math Problems

Here are a few problems that involve passing object references as parameters. You may want to review tutorial 2 on arrays, the new operator and assigning variable values. Formatted output requires DecimalFormat class and keyboard input requires file io class!

  1. Write a method to interchange any two rows of a two-dimensional array passed to it.
  2. Write a method to determine if a two-dimensional array passed to it is symmetric, that is A[i][j]==A[j][i] for all valid i and j.
  3. Write method to transpose, a matrix, that is your method should make its rows into columns, and vice-versa.
  4. Write a method to multiply two conformable matrices. Use your method to find the product P=M x M x M for the matrix M given by {{4,9,2},{3,5,7},{8,1,6}}
  5. Write a program that allows you to input 10 numbers into an array. Then create a method that will return and print the average, sum, smallest value, largest value and printout those below the average and values above average.
  6. Write a program allows you to create the following methods [Assume that your array has 10 elements]:
      A). A method to input the content of an array.
    B). A method to return the sum.
    C). A method to return the average
    D). A method to return the average of negative numbers.
    E). A method to return the average of positive numbers.
    F). A method to return the average, smallest and largest.
  7. Write a program that allows you fill a tabulated 3x3 matrix with random numbers range from 0 to 50. Write a method that will display a message BINGO if the array element has at least 2 numbers divisible by 5.

Encapsulation

This tutorial discusses the first fundamental object oriented principle which is encapsulation of information and functionality within the object.

Encapsulation

Encapsulation is the ability of an object to place a boundary around its properties (ie. data) and methods (ie. operations). Programs written in older languages suffered from side effects where variables sometimes had their contents changed or reused in unexpected ways. Some older languages even allowed branching into procedures from external points. This led to 'spaghetti' code that was difficult to unravel, understand and maintain. Encapsulation is one of three basic principles within object oriented programming languages.

Object variables can be hidden completely from external access. These private variables can only be seen or modified by use of object accessor and mutator methods. Access to other object variables can be allowed but with tight control on how it is done. Methods can also be completely hidden from external use. Those that are made visible externally can only be called by using the object's front door (ie. there is no 'goto' branching concept).

Class Specification

A class specifies the properties (data) and methods (actions) that objects can work with. It is a template or prototype for each of many objects made to the class design. The syntax for a class is:

["public"] ["abstract"|"final"]"class" class_name
["extends" object_name] ["implements" interface_name]
"{"
// properties declarations
// behavior declarations
"}"

The first optional group indicates the visibility or scope of accessibility from other objects. public means visible everywhere. The default (ie. omitted) is package (aka friendly) or visible within the current package only.

The second optional group indicates the capability of a class to be inherited or extended by other classes. abstract classes must be extended and final classes can never be extended by inheritance. The default (ie. omitted) indicates that the class may or may not be extended at the programmers discretion.

The third option of extends is described in the tutorial on inheritance.

The fourth option of implements is described in the tutorial on interfaces.

Let's use a simple box as an example of a class specification. The box has length, width and height properties as well as a method for displaying the volume. An example of how this might be specified in Java is:

public class Box
{
// what are the properties or fields
private int length;
private int width;
private int height;

// what are the actions or methods
public void setLength(int p)
{length = p;}

public void setWidth(int p)
{width = p;}

public void setHeight(int p)
{height = p;}

public int displayVolume()
{System.out.println(length*width*height);}
}

Note1: There is no main method in a class defining template!
Note2: Class names begin with a capital. Convention uses lowercase for all other names.

Properties (aka Field Variables)

Classes without properties or behaviour are not very useful. Properties in Java are sometimes called field variables. To declare a property use the following syntax:

[ "public" | "private" | "protected" ] [ "final" ]
[ "static" | "transient" | "volatile" ]
data_type var_name [ = var_initializer ] ";"

The items in the first optional group indicate the 'visibility' or accessibility from other objects. public means visible everywhere (global). private indicates accessible only to this class and nested classes. protected means visible to this class or inherited (ie. extended) classes only. The default (keyword omitted) is friendly or visible within the current package (folder) only.

final indicates continuous retention and unchangeable after initial assignment (ie. it is read only or constant).

The third optional group indicates how long a value is retained in the variable. static indicates that the value is shared by all members of the class and exists for all runtime. Static members can be referenced without creating an instance of the class. transient prevents the variable from being transferred during a serial operation such as file i/o. volatile is used in threading to prevent overwrite issues.

The data_type is one of the primitive types listed in tutorial 2 and can be optionally initialized.

Many programmers choose to make all properties private and force access through accessors and mutators which can include validation steps.

Types of Methods

Class behaviour are represented in Java by methods. To declare a method use the following syntax:

[ "public" | "private" | "protected" ] [ "final" ]
[ "static" | "abstract" | "native" ]
return_data_type method_name "(" parameter_list ")"
"{"
// some defining actions
"}"

Accessibility keywords are the same as for properties. The default (ie. omitted) is package (aka friendly) or visible within the current package only.

static methods are shared and retained. abstract methods must be redefined on inheritance. native methods are written in C but accessible from Java.

The return_data_type defines the type of value that the calling routine receives from the object (the reply message in object terminology). It can be any of the primitive types or the reserved word void (default value) if no message is to be returned. The statement return variablename; is used to declare the value to be returned to the calling routine.

The parameter_list can contain from zero to many entries of datatype variablename pairs. Entries are separated by commas. Parameters are passed by value, thus upholding the encapsulation principle by not allowing unexpected changes or side effects. Object references (such as arrays) can also be passed. Some examples of method header parameter lists are:

public static void example1() { }
public static int add2(int x) { x+=2; return x; }
public static double example3(int x, double d) { return x*d; }
public static void example4(int x, int y, boolean flagger) { }
public static void example5(int arr[]) { } // note: this is an object

Constructor methods allow class objects to be created with fields initialized to values as determined by the methods' parameters. This allows objects to start with values appropriate to use (eg. salary set to a base level or employeeNumber set to an incrementing value to guarantee uniqueness). For our simple box class:

public Box() // default box is point
{length = 0; width = 0; height = 0;}
public Box(int l,int w,int h) // allows giving initial size
{length = l; width = w; height = h;}

Note that there is no class keyword or return datatype keyword. Also the method name is the same as the class name. This is what marks the fragment as a constructor method. If no constructor method is defined for a class, a default constructor is automatically used to initialize all fields to 0, false or unicode(0) as appropriate to the datatype. Constructors can be overloaded in the same way that instance methods are.

One clever programming device is to declare the constructor with no parameters as private and use it to initialize all properties. Then other constructors can first call it using this() and then do their own specific property validations/initialization.

Accessor (or observer) methods read property (ie field variable) values and are conventionally named getFoobar() or whatever the property is called.

Mutator (or transformer) methods set property values and are often named setFoobar() etc. Mutators can be used to ensure that the property's value is valid in both range and type.

It is good programming practice to include accessor and mutator methods for each property in the class. They are perfect example of object encapsulization. The exceptions to writing accessor/mutator methods for each property is for those that are used only within the class itself or for properties that are set in more complex ways.

Helper methods are those routines that are useful within the class methods but not outside the class. They can help in code modularization. Normally they are assigned private access to restrict use.

Overloading and Recursion

Overloaded methods are methods with the same name signature but either a different number of parameters or different types in the parameter list. For example 'spinning' a number may mean increase it, 'spinning' an image may mean rotate it by 90 degrees. By defining a method for handling each type of parameter you achieve the effect that you want.

Overridden methods are methods that are redefined within an inherited class.

Recursive methods are methods that are defined in terms of themselves. A classic recursion is factorials where n factorial is the product of n and all the products before it down to one. In Java this could be programmed as:

class Factorial
{
int factorial(int n)
{
if (n==1) {return 1};
return (n * factorial(n-1));
}
}

Object Creation and Destruction

To create an object of a particular class use the creation method after the particular class has already been specified. For example, now that there is a constructor for the Box class you can make specific instances or discrete copies of a box by using the assignment operator and the new memory allocation operator as in:

Box box_1 = new Box(3,4,5);

Note: Once a class has been created, a datatype exists with the same name.

You do not need to destroy or remove an object when it is no longer needed. Java automatically flags unused objects and applies garbage collection when appropriate. However you may occasionally need to use the finalize method to insure that a non-Java resource such as a file handle or a window font character is released first. The general form is:

void finalize()
{
//cleanup code goes here
}

Inner Classes

Inner classes are classes nested inside another class. They have access to the outer class fields and methods even if marked as private. Inner classes are used primarily for data structures, helper classes, and event handlers. A brief example of how an inner class can be used as a data structure is:

public class Main2
{
class Person
{
// inner class defines the required structure
String first;
String last;
}
// outer class creates array of person objects with specific properties
// the objects can be referenced by personArray[1].last for example
Person personArray[] = {new Person(), new Person(), new Person()};
}

Project Organization

It is standard programming practice to write separate files for the class templates and the driver or main user programs. This allows separate compilation as well as class reuse by other driver programs. A class file can contain more than one associated class but normally its filename is that of the first defined file. A driver program is named the same as the class that contains the main(). It may contain other classes as well.

Project: Circle Class

At this point we need a small project to test your ability to create a class and then use it to create an object that does something! Circle is a class with properties radius, area, and diameter and methods setRadius(), getRadius(), calcDiameter(), calcArea(). Use double precision for everything. For the mathematically challenged, the area of a circle is PI r squared (NO! pie are round, cake are square ;-] ;-] ). Use 3.14 for PI. Test with a value of three for the radius. The diameter should read as 6 and the area as 28.25999...

Since this is such a short program, you may want to use only one file say MakeCircle.java that contains both the main (or driver) and the Circle class. Once it is working, see if you can factor it into two files (Circle and MakeCircle) and compile separately, (the Circle class file first). As an enhancement, you may want to add a command line interpreter to get the radius for the driver to use.

String Manipulation

String manipulation forms the basis of many algorithms and utilities. Input validation, text analysis and file conversions are several direct applications of string manipulation. This tutorial explores some of the basics needed. Unless otherwise noted, the following classes are contained in the java.lang library.

NOTE: For the following method parameters the prefix g indicates string, i indicates integer and c indicates character types.

The String Class

String class objects work with complete strings instead of treating them as character arrays as some languages do.

Accessor methods: length(), charAt(i), getBytes(), getChars(istart,iend,gtarget[],itargstart), toCharArray(), valueOf(g,iradix), substring(iStart [,iEndIndex)]) [returns up to but not including iEndIndex]

Modifier methods: toLowerCase(), toUpperCase(), trim(), concat(g), replace(cWhich, cReplacement). The method format(gSyn,g) uses c-like printf syntax for fixed fields if required in reports.

Boolean test methods: contentEquals(g), endsWith(g), equals(g), equalsIgnoreCase(g), matches(g), regionMatches(i1,g2,i3,i4), regionMatches(bIgnoreCase,i1,g2,i3,i4), startsWith(g)

Integer test methods: compareTo(g) [returns 0 if object equals parameter, -1 if object is before parameter in sort order, +1 if otherwise], indexOf(g) [returns position of first occurrence of substring g in the string, -1 if not found], lastIndexOf(g) [returns position of last occurrence of substring g in the string, -1 if not found], length().

String class objects are immutable (ie. read only). When a change is made to a string, a new object is created and the old one is disused. This causes extraneous garbage collection if string modifier methods are used too often. The StringBuffer class should be used instead of String objects in these cases.

Warning: Since strings are stored differently than other data (as a memory address), you can't use the == operator for comparison. However the string methods equals() and equalsIgnoreCase() do the required comparison. A simple example is:

String aName = "Roger"; String bName = "Roger";
if (aName == bName) {System.out.println('== worked')};
if (aName.equals(bName)) {System.out.println('equals worked')};

Here is a program fragment to validate characters in a string, possibly from data entry or from a file. Regular Expression techniques can also be used for validation.

String testString="agjSDRoir";
String validChars = "atgc";
testString=testString.toLowerCase(); // make sure case is correct
for (int i=0;i

The String Buffer Class

StringBuffer class objects allow manipulation of strings without creating a new object each time a manipulation occurs. Examples of setting up a string buffer variable are:

StringBuffer aString = new StringBuffer("the start value"); // sets value
StringBuffer nulString = new StringBuffer(6); // explicitly sets size
StringBuffer defString = new StringBuffer(); // sets size to default of 16

Accessor methods: capacity(), length(), charAt(i)

Modifier methods: ensureCapacity(), setLength(), append(g), delete(i1, i2), deleteCharAt(i), insert(iPosn, g), setCharAt(iposn, c), replace(i1,i2,gvalue), reverse(), toString(g)

The String Buider Class

StringBuilder class methods are similar to StringBuffer ones but they are unsychronized (ie not for multithreaded apps). They are also much faster. Examples of setting up a string buffer variable are:

StringBuilder aString = new StringBuilder("the start value"); // sets value
StringBuilder nulString = new StringBuilder(6); // explicitly sets size
StringBuilder defString = new StringBuilder(); // sets size to default of 16

Accessor methods: capacity(), length(), charAt(i), indexOf(g), lastIndexOf(g)

Modifier methods: append(g), delete(i1, i2), insert(iPosn, g), getChars(i), setCharAt(iposn, c), substring(), replace(i1,i2,gvalue), reverse(), trimToSize(g ), toString(g)

The String Tokenizer Class [java.util library]

Many text manipulation utilities require a tokenizer function which breaks up lines of text into subunits called tokens based on specific delimiters or break characters. The most common delimiter is whitespace which yields words as the tokens. Java has a very useful StringTokenizer class to perform this type of task.

StringTokenizer class objects may be created by one of three constructor methods depending on the parameters used. If a string is used as a single parameter, it is the source text to be broken at the default set of delimiters (space, tab, newline, cr, formfeed aka whitespace). If a second string is also passed, it is assumed to be a set of delimiting characters. Use the escaper \ character to represent the string quote character " or non-typeable delimiters such as tab (\t). If a true flag is added as a third parameter, any delimiters found are also returned as string tokens.

Note: If the information to be tokenized is coming from a file, the StreamTokenizer object may be a more efficient choice.

The StringTokenizer methods are int countTokens(), boolean hasMoreTokens() and String nextToken().

import java.util.*;
public class Test
{
public static void main(String args[])
{
int idx = 0; int tokenCount;
String words[] = new String [500];
String message="The text of the message to be broken up for analysis";
StringTokenizer st = new StringTokenizer(message);
tokenCount = st.countTokens();
System.out.println("Number of tokens = " + tokenCount);
while (st.hasMoreTokens()) // make sure there is stuff to get
{ words[idx] = st.nextToken(); idx++; }
for (idx=0;idx

Regular Expressions [java.util.regex library]

Regular expressions are a way to describe a set of strings based on common characteristics shared by each string in the set (ie. by pattern matching). They can be used as a tool to search, edit or manipulate text or data. One common use is validation of data entry strings. All classes related to regular expressions are found in the java.util.regex package which must be imported.

Java regular expression patterns use a syntax similar to the one used by perl. The best references are found at sun.com and RegExp.info. Simple examples of the use of regular expressions are:

Pattern p = Pattern.compile("a*b");
Matcher m = p.matcher("aaaaab");
boolean b = m.matches();

As a convenience for a one-time use situation the matches method simplifies the syntax (but does not precompile the pattern).

boolean b = Pattern.matches("a*b", "aaaaab");

As an aid to understanding the syntax of regular expressions and as a development tool, I strongly recommend downloading the test harness.

String Applications

Analyzing, searching and reformatting text is often required in task automation. Simple analysis could be used for word counts, concordance, spell checking, reading difficulty analysis, input validity, etc. Searching is done to find relevant terms. Reformatting of text for new file formats is a common task.

Many tasks involve parsing a line using either field positions or delimiters. A useful task would be to create reuseable methods for txtAt(start,end), wordAt(start,length), txtBefore(delim) and txtAfter(delim). These methods would return null if linereturn was reached before the delimiter or if position parameters caused a length violation. Each method would use some of the string class methods mentioned above.

Simple processing such as removing unwanted characters from strings or translating them is an easy first exercise in string manipulation. cleanchr1.java and cleanchr2.java show two approaches to simple string manipulation.

Note: Each of the following projects in this tutorial will be reused several times as other important topics are introduced. For now the workspace for each project will require hard coding of several lines of data into a string array.

Project: Word Counting

WordCount uses text parsing or tokenization to analyze text into counts of each distinct word unit. This has many practical applications in spell checking, document difficulty analysis, cryptology and file compression. A first approach is to create an array of words, add to the end and search from the front. The first refinement for larger lists is to use an insertion sort and binary search. A further refinement. once file IO has been covered, is to keep the parsed words in files so that array size is not an issue -- ie. large documents can be handled.

Start with the string tokenizer example. Add a second parameter to the tokenizer that specifies explicitly all delimiters needed (punctuation is missing in the default constructor). Lowercase (desense) all parsed words. Now rework the example to accept an array of text rather than a single line. Add a linear search for the word in the word array prior to adding it. If found, increment its count else add it to the list with a count of 1.

The output should display the word array with its associated word count. Make sure to use a fixed field format that allows sorting of the report by another utility. A suggestion is ### wordstring. You may want to review the DecimalFormat Class for specifics.

Note: WordCount1.java is in the source code package located below.

The second phase of the word count project will add a text file io class. It will then be extended with a GUI to produce a useful utility - a word count reporter.

Project: Cipher Text Preparation

The Prep class modifies plain text into the common cipher format of uppercased five letter groups for transmission. This class will be reused in a later case study that enciphers the prepared text using a variety of coding techniques.

Note: Prep1.java is in the source code package located below.

The second phase of the cipher text preparation project will add a text file io class. It will then be extended with two GUIs. The first GUI will be screen oriented for applets. The second will be batch file oriented.

Project: XHTML Analysis

This project uses pattern recognition to identify elements, tags and attributes within XHTML documents . This will be used in a later project to spot deprecated components and attributes that are better represented with CSS properties. For now you will simply count the number of each type of tag. Check for matched tags (and nesting if you can). Output each attribute and its value.

Because tokenization is awkward for XHTML, it is easier to build an ad-hoc pattern recognizer to spot both tag and attribute formats. This takes care of the

or


forms of tags. Regular expression classes can be used to make the pattern recognizer very compact. Take special care to watch for tags wrapped on multiple lines.

Note: TagScan1 is in the source code package located below.

The analysis project will be extended with file io and a GUI will be added to produce a two useful utility - a search word extractor for a site search engine and the obsolete component finder. A utility can also be written to validate internal links.

Inheritance & Polymorphism

This tutorial discusses the second and third fundamental object oriented programming principles of inheritance and polymorphism.

Inheritance

Inheritance is the capability of a class to use the properties and methods of another class while adding its own functionality. An example of where this could be useful is with an employee records system. You could create a generic employee class with states and actions that are common to all employees. Then more specific classes could be defined for salaried, commissioned and hourly employees. The generic class is known as the parent (or superclass or base class) and the specific classes as children (or subclasses or derived classes). The concept of inheritance greatly enhances the ability to reuse code as well as making design a much simpler and cleaner process.

Inheritance in Java

Java uses the extends keyword to set the relationship between a child class and a parent class. For example using our Box class from tutorial 4:

public class GraphicsBox extends Box

The GraphicsBox class assumes or inherits all the properties of the Box class and can now add its own properties and methods as well as override existing methods. Overriding means creating a new set of method statements for the same method signature (name and parameters). For example:

// define position locations
private int left;
private int top;
// override a superclass method
public int displayVolume() {
System.out.println(length*width*height);
System.out.println("Location: "+left+", "+top);
}

When extending a class constructor you can reuse the superclass constructor and overridden superclass methods by using the reserved word super. Note that this reference must come first in the subclass constructor. The reserved word this is used to distinguish between the object's property and the passed in parameter.

    GraphicsBox(l,w,h,left,top)
{
super (l,w,h);
this.left = left;
this.top = top;
}
public void showObj()
{System.out.println(super.showObj()+"more stuff here");}

The reserved word this can also be used to reference private constructors which are useful in initializing properties.

Special Note:You cannot override final methods, methods in final classes, private methods or static methods.

The Object Class

The Object class is the superclass of Java. All other classes are subclasses of the Object class. The object class includes methods such as:

clone()finalize()hashCode()toString()
copy(Object src)getClass()notifyAll() wait()

Abstract Classes

As seen from the previous example, the superclass is more general than its subclass(es). The superclass contains elements and properties common to all of the subclasses. The previous example was of a concrete superclass that objects can be made from. Often, the superclass will be set up as an abstract class which does not allow objects of its prototype to be created. In this case only objects of the subclass are used. To do this the reserved word abstract is included in the class definition.

Abstract methods are methods with no method statements. Subclasses must provide the method statements for their particular meaning. If the method was one provided by the superclass, it would require overriding in each subclass. And if one forgot to override, the applied method statements may be inappropriate.

public abstract class Animal  // class is abstract
{
private String name;
public Animal(String nm)
{ name=nm; }
public String getName() // regular method
{ return (name); }
public abstract void speak(); // abstract method - note no {}
}

Abstract classes and methods force prototype standards to be followed (ie. they provide templates).

Interfaces

Java does not allow multiple inheritance for classes (ie. a subclass being the extension of more than one superclass). To tie elements of different classes together Java uses an interface. Interfaces are similar to abstract classes but all methods are abstract and all properties are static final. As an example, we will build a Working interface for the subclasses of Animal. Since this interface has the method called work(), that method must be defined in any class using Working.

public interface Working
{
public abstract void work();
}

When you create a class that uses an interface, you reference the interface with the reserved word implements Interface_list. Interface_list is one or more interfaces as multiple interfaces are allowed. Any class that implements an interface must include code for all methods in the interface. This ensures commonality between interfaced objects.

public class WorkingDog extends Dog implements Working
{
public WorkingDog(String nm)
{
super(nm); // builds ala parent
}
public void work() // this method specific to WorkingDog
{
speak();
System.out.println("I can herd sheep and cows");
}
}

Interfaces can be inherited (ie. you can have a sub-interface). As with classes the extends keyword is used. Multiple inheritance can be used with interfaces.


Polymorphism

Polymorphism is the capability of an action or method to do different things based on the object that it is acting upon. This is the third basic principle of object oriented programming. We have already used two types of polymorphism (overloading and overriding). Now we will look at the third: dynamic method binding.

Assume that three subclasses (Cow, Dog and Snake) have been created based on the Animal abstract class, each having their own speak() method.

public class AnimalReference
{
public static void main(String args[])
Animal ref // set up var for an Animal
Cow aCow = new Cow("Bossy"); // makes specific objects
Dog aDog = new Dog("Rover");
Snake aSnake = new Snake("Earnie");

// now reference each as an Animal
ref = aCow;
ref.speak();
ref = aDog;
ref.speak();
ref = aSnake;
ref.speak();
}

Notice that although each method reference was to an Animal (but no animal objects exist), the program is able to resolve the correct method related to the subclass object at runtime. This is known as dynamic (or late) method binding.

Arrays of Subclasses

As with arrays of primitive types, arrays of objects allow much more efficient methods of access. Note in this example that once the array of Animals has been structured, it can be used to store objects of any subclass of Animal. By making the method speak() abstract, it can be defined for each subclass and any usage will be polymorphic (ie. adapted to the appropriate object type at runtime). It now becomes very easy to rehearse the speak() method for each object by object indexing.

public class AnimalArray
{
public static void main(String args[])
Animal ref[] = new Animal[3]; // assign space for array
Cow aCow = new Cow("Bossy"); // makes specific objects
Dog aDog = new Dog("Rover");
Snake aSnake = new Snake("Earnie");

// now put them in an array
ref[0] = aCow; ref[1] = aDog; ref[2] = aSnake;

// now demo dynamic method binding
for (int x=0;x<3;++x) { ref[x].speak(); }
}

Casting Objects

One of the difficulties of using a superclass array to hold many instances of subclass objects is that one can only access properties and methods that are in the superclass (ie. common to all). By casting an individual instance to its subclass form one can refer to any property or method. But first take care to make sure the cast is valid by using the operation instanceof. Then perform the cast. As an example using the above Animal class:

if (ref[x] instanceof Dog) // ok right type of object
{
Dog doggy = (Dog) ref[x]; // cast the current instance to its subclass
doggy.someDogOnlyMethod();
}