JEDI - Introduction - To.java - Programming.vol.2
JEDI - Introduction - To.java - Programming.vol.2
Introduction to
Programming
II
Version 2.0
May 2006
Table of Contents
1 Review of Basic Concepts in Java........................................................................14
1.1 Objectives................................................................................................14
1.2 Object-Oriented Concepts...........................................................................14
1.2.1 Object-Oriented Design....................................................................... 14
1.2.2 Class.................................................................................................14
1.2.3 Object...............................................................................................15
1.2.4 Attribute............................................................................................15
1.2.5 Method..............................................................................................15
1.2.6 Constructor........................................................................................15
1.2.7 Package ............................................................................................15
1.2.8 Encapsulation.....................................................................................15
1.2.9 Abstraction........................................................................................15
1.2.10 Inheritance.......................................................................................16
1.2.11 Polymorphism...................................................................................16
1.2.12 Interface..........................................................................................16
1.3 Java Program Structure..............................................................................17
1.3.1 Declaring Java Classes.........................................................................17
1.3.2 Declaring Attributes............................................................................ 17
1.3.3 Declaring Methods.............................................................................. 18
1.3.4 Declaring a Constructor.......................................................................18
1.3.5 Instantiating a Class............................................................................19
1.3.6 Accessing Object Members...................................................................19
1.3.7 Packages...........................................................................................19
1.3.8 The Access Modifiers........................................................................... 20
1.3.9 Encapsulation.....................................................................................20
1.3.10 Inheritance.......................................................................................21
1.3.11 Overriding Methods...........................................................................21
1.3.12 Abstract Classes and Methods.............................................................22
1.3.13 Interface..........................................................................................23
1.3.14 The this Keyword..............................................................................24
1.3.15 The super Keyword............................................................................25
1.3.16 The static Keyword............................................................................26
1.3.17 The final Keyword.............................................................................27
1.3.18 Inner Classes....................................................................................28
1.4 Exercises..................................................................................................29
1.4.1 Multiplication Table.............................................................................29
1.4.2 Greatest Common Factor (GCF)............................................................29
1.4.3 Shapes..............................................................................................29
1.4.4 Animals.............................................................................................29
2 Exceptions and Assertions.................................................................................30
2.1 Objectives................................................................................................30
2.2 What are Exceptions?.................................................................................30
2.2.1 Introduction.......................................................................................30
2.2.2 The Error and Exception Classes........................................................... 30
2.2.3 An Example........................................................................................31
2.3 Catching Exceptions...................................................................................31
2.3.1 The try-catch Statements.....................................................................31
2.3.2 The finally Keyword.............................................................................34
2.4 Throwing Exceptions..................................................................................36
2.4.1 The throw Keyword.............................................................................36
2.4.2 The throws Keyword............................................................................36
2.5 Exception Categories..................................................................................37
2.5.1 Exception Classes and Hierarchy...........................................................37
2.5.2 Checked and Unchecked Exceptions...................................................... 38
2.5.3 User-Defined Exceptions......................................................................38
2.6 Assertions.................................................................................................39
2.6.1 What are Assertions?...........................................................................39
2.6.2 Enabling or Disabling Assertions........................................................... 39
1.4 Animals...............................................................................................194
Chapter 2 Exercises........................................................................................195
2.1 Hexadecimal to Decimal.........................................................................195
2.2 Printing a Diamond...............................................................................196
Chapter 3 Exercises........................................................................................197
3.1 Greatest Common Factor.......................................................................197
3.2 Sequential Representation of an Integer Queue........................................ 197
3.3 Linked Representation of an Integer Queue..............................................199
3.4 Address Book.......................................................................................200
Chapter 4 Exercises........................................................................................201
4.1 Evaluate Expression..............................................................................201
4.2 Palindrome...........................................................................................201
4.3 Notepad...............................................................................................201
Chapter 5 Exercises........................................................................................202
5.1 Spaces to Underscore............................................................................202
5.2 Draw Triangle.......................................................................................203
Chapter 6 Exercises........................................................................................204
6.1 Insertion Sort.......................................................................................204
6.2 Selection Sort.......................................................................................204
6.3 Merge Sort ..........................................................................................205
6.4 Quick Sort............................................................................................206
Chapter 7 Exercises........................................................................................207
7.1 Tic-Tac-Toe..........................................................................................207
7.2 Calculator............................................................................................208
Chapter 8 Exercises........................................................................................210
8.1 Tic-Tac-Toe..........................................................................................210
8.2 Calculator............................................................................................213
Chapter 9 Exercises........................................................................................218
9.1 Banner................................................................................................218
Chapter 10 Exercises......................................................................................219
10.1 Trivia Server.......................................................................................219
Chapter 11 Exercises......................................................................................222
11.1 One-Player Tic-Tac-Toe Applet..............................................................222
Chapter 12 Exercises......................................................................................227
12.1 Simple Encryption...............................................................................227
Chapter 13 Exercises......................................................................................228
13.1 Swapping...........................................................................................228
Appendix B : Machine Problems........................................................................... 229
Machine Problem 1: Polynomial Arithmetic........................................................ 229
Machine Problem 2: My Domino!......................................................................230
1.1 Objectives
Before moving on to other interesting features of Java, let us first review some of the
things you've learned in your first programming course. This lesson provides a brief
discussion of the different object-oriented concepts in Java.
1.2.2 Class
A class allows you to define new data types. It serves as a blueprint, which is a model for
the objects you create based on this new data type.
The template student is an example of a class. We can define every student to have a set
of qualities such as name, student number and school level. We can also define students
1.2.3 Object
An object is an entity that has a state, behavior and identity with a well-defined role in
problem space. It is an actual instance of a class. Thus, it is also known as an instance.
It is created everytime you instantiate a class using the new keyword. In a student
registration system, an example of an object would be a student entity, say Anna. Anna
is an object of the class student. Thus, the qualities and abilities defined in the student
template are all applicable to Anna.
For simplicity, you can think of a class as a more general term compared to an object.
1.2.4 Attribute
An attribute refers to the data element of an object. It stores information about the
object. It is also known as a data member, an instance variable, a property or a data
field. Going back to the student registration system example, some attributes of a
student entity include name, student number and school level.
1.2.5 Method
A method describes the behavior of an object. It is also called a function or a procedure.
For example, possible methods available for a student entity are enroll and attend
school.
1.2.6 Constructor
A constructor is a special type of method used for creating and initializing a new object.
Remember that constructors are not members (i.e., attributes, methods or inner classes
of an object).
1.2.7 Package
A package refers to a grouping of classes and/or subpackages. Its structure is analogous
to that of a directory.
1.2.8 Encapsulation
Encapsulation refers to the principle of hiding design or implementation information that
are not relevant to the current object.
1.2.9 Abstraction
While encapsulation is hiding the details away, abstraction refers to ignoring aspects of a
subject that are not relevant to the current purpose in order to concentrate more fully on
those that are.
1.2.10 Inheritance
Inheritance is a relationship between classes wherein one class is the superclass or the
parent class of another. It refers to the properties and behaviors received from an
ancestor. It is also know as a "is-a" relationship. Consider the following hierarchy.
SuperHero
FlyingSuperHero UnderwaterSuperHero
1.2.11 Polymorphism
Polymorphism is the ability of an object to assume may different forms. Literally, "poly"
means many while "morph" means form. Referring to the previous example for
inheritance, we see that a SuperHero object can also be a FlyingSuperHero object or an
UnderwaterSuperHero object.
1.2.12 Interface
An interface is a contract in the form of a collection of method and constant declarations.
When a class implements an interface, it promises to implement all of the methods
declared in that interface.
<classDeclaration> ::=
<modifier> class <name> {
<attributeDeclaration>*
<constructorDeclaration>*
<methodDeclaration>*
}
where
<modifier> is an access modifier, which may be combined with other types of modifier.
Coding Guidelines:
* means that there may be 0 or more occurrences of the line where it was applied to.
<description> indicates that you have to substitute an actual value for this part instead
of typing it as ease.
Remember that for a top-level class, the only valid access modifiers are public and
package (i.e., if no access modifier prefixes the class keyword).
class SuperHero {
String superPowers[];
void setSuperPowers(String superPowers[]) {
this.superPowers = superPowers;
}
void printSuperPowers() {
for (int i = 0; i < superPowers.length; i++) {
System.out.println(superPowers[i]);
}
}
}
<attributeDeclaration> ::=
<modifier> <type> <name> [= <default_value>];
<type> ::=
byte | short | int | long | char | float | double | boolean
| <class>
Coding Guidelines:
[] indicates that this part is optional.
Here is an example.
String college;
}
<methodDeclaration> ::=
<modifier> <returnType> <name>(<parameter>*) {
<statement>*
}
<parameter> ::=
<parameter_type> <parameter_name>[,]
For example:
class MethodDemo {
int data;
int getData() {
return data;
}
void setData(int data) {
this.data = data;
}
void setMaxData(int data1, int data2) {
data = (data1>data2)? data1 : data2;
}
}
<constructorDeclaration> ::=
<modifier> <className> (<parameter>*) {
<statement>*
}
Coding Guidelines:
The name of the constructor should be the same as the class name.
The only valid <modifier> for constructors are public, protected, and private.
Constructors do not have return values.
class ConstructorDemo {
private int data;
public ConstructorDemo() {
data = 100;
}
ConstructorDemo(int data) {
this.data = data;
}
}
class ConstructObj {
int data;
ConstructObj() {
/* initialize data */
}
public static void main(String args[]) {
ConstructObj obj = new ConstructObj(); //instantiation
}
}
<object>.<member>
The next example is based on the previous one with additional statements for accessing
members and an additional method.
class ConstructObj {
int data;
ConstructObj() {
/* initialize data */
}
void setData(int data) {
this.data = data;
}
public static void main(String args[]) {
ConstructObj obj = new ConstructObj(); //instantiation
obj.setData(10); //access setData()
System.out.println(obj.data); //access data
}
}
1.3.7 Packages
To indicate that the source file belongs to a particular package, we use the following
syntax:
<packageDeclaration> ::=
package <packageName>;
<importDeclaration> ::=
import <packageName.elementAccessed>;
With this, your source code should have the following format:
[<packageDeclaration>]
<importDeclaration>*
<classDeclaration>+
Coding Guidelines:
+ indicates that there may be 1 or more occurrences of the line where it was applied to.
Here is an example.
package registration.reports;
import registration.processing.*;
//imports all classes in registration.processing package
import java.util.List;
import java.lang.*; //imported by default
//imports all classes in java.lang
class MyClass {
/* details of MyClass */
}
1.3.9 Encapsulation
Hiding elements of the implementation of a class can be done by making the members
that you want to hide private.
The following example hides the secret field. Note that this field is indirectly accessed by
other programs using the getter and setter methods.
class Encapsulation {
private int secret; //hidden field
public boolean setSecret(int secret) {
if (secret < 1 || secret > 100) {
return false;
}
this.secret = secret;
return true;
}
public getSecret() {
return secret;
}
}
If you do not want other classes to modify the secret field, you can set the access
modifier of the setSecret() method to be private.
1.3.10 Inheritance
To create a child class or a subclass based on an existing class, we use the extends
keyword in declaring the class. A class can only extend one parent class.
For example, the Point class below is the superclass of the ColoredPoint class.
import java.awt.*;
class Point {
int x;
int y;
}
This is different from method overloading. Method overloading is briefly discussed in the
subsection on the this keyword.
class Superclass {
void display(int n) {
System.out.println("super: " + n);
}
}
class OverrideDemo {
public static void main(String args[]) {
Subclass SubObj = new Subclass();
Superclass SuperObj = SubObj;
SubObj.display(3);
((Superclass)SubObj).display(4);
}
}
The method called is determined by the actual data type of the object that invoked the
method.
The access modifier for the methods need not be the same. However, the access modifier
of the overriding method must either have the same access modifier as that of the
overridden method or a less restrictive access modifier.
Consider the next example. Check out which of the following overridding methods would
cause a compile time error to occur.
class Superclass {
void overriddenMethod() {
}
}
The overriddenMethod() in Superclass has the default/package access modifier. The only
modifier more restrictive than this is private. Thus, Subclass4 causes a compiler error
because it tries to override overriddenMethod() in Superclass with a more restrictive
modifier private.
Classes that extends an abstract class should implement all abstract methods. If not the
subclass itself should be declared abstract.
Coding Guidelines:
Note that declaring an abstract method is almost similar to declaring a normal class
except that an abstract method has no body and the header is immediately terminated
by a semicolon (;).
For example:
1.3.13 Interface
Declaring an interface is basically declaring a class but instead of using the class
keyword, the interface keyword is used. Here is the syntax.
<interfaceDeclaration> ::=
<modifier> interface <name> {
<attributeDeclaration>*
[<modifier> <returnType> <name>(<parameter>*);]*
}
Coding Guidelines:
Attributes are implicitly static and final and must be initialized with a constant value.
Like in declaring a top-level class, the only valid access modifiers are public and package
(i.e., if no access modifier prefixes the class keyword).
A class can implement an existing interface by using the implements keyword. This class
is forced to implement all of the interface's methods. A class may implement more than
one interface.
interface MyInterface {
void iMethod();
}
class MyClass1 implements MyInterface {
public void iMethod() {
System.out.println("Interface method.");
}
void myMethod() {
System.out.println("Another method.");
}
}
class InterfaceDemo {
public static void main(String args[]) {
MyClass1 mc1 = new MyClass1();
MyClass2 mc2 = new MyClass2();
mc1.iMethod();
mc1.myMethod();
mc2.iMethod();
}
}
As an example for the first purpose, consider the following code wherein the variable
data serves as an attribute and a local parameter at the same time.
class ThisDemo1 {
int data;
void method(int data) {
this.data = data;
/* this.data refers to the attribute
while data refers to the local variable */
}
}
The following example demonstrates how this object is implicitly referred to when its
non-static members are invoked.
class ThisDemo2 {
int data;
void method() {
System.out.println(data); //this.data
}
void method2() {
method(); //this.method();
}
}
Before looking at another example, let's first review the meaning of method overloading.
A constructor like a method can also be overloaded. Different methods within a class can
share the same name provided their parameter lists are different. Overloaded methods
must differ in the number and/or type of their parameters. The next example has
overloaded constructors and the this reference can be used to refer to other versions of
the constructor.
class ThisDemo3 {
int data;
ThisDemo3() {
this(100);
}
ThisDemo3(int data) {
this.data = data;
}
}
Coding Guidelines:
Call to this() should be the first statement in the constructor.
The following program demonstrates how the super reference is used to call superclass
constructors.
class Person {
String firstName;
String lastName;
Person(String fname, String lname) {
firstName = fname;
lastName = lname;
}
}
Coding Guidelines:
super() refers to the immediate superclass. It should be the first statement in the
subclass's constructor.
The keyword can also be used to refer to superclass members as shown in the following
example.
class Superclass{
int a;
void display_a(){
System.out.println("a = " + a);
}
}
class SuperDemo {
public static void main(String args[]){
Superclass SuperObj = new Superclass();
Subclass SubObj = new Subclass();
SuperObj.a = 1;
SubObj.a = 2;
SubObj.set_super_a(3);
SuperObj.display_a();
SubObj.display_a();
SubObj.display_super_a();
System.out.println(SubObj.a);
}
}
A class variable behaves like a global variable. This means that the variable can be
accessed by all instances of the class.
Class methods may be invoked without creating an object of its class. However, they can
only access static members of the class. In addition to this, they cannot refer to this or
super.
The static keyword can also be applied to blocks. These are called static blocks. These
blocks are executed only once, when the class is loaded. These are usually used to
initialize class variables.
class Demo {
static int a = 0;
static void staticMethod(int i) {
System.out.println(i);
}
static { //static block
System.out.println("This is a static block.");
a += 1;
}
}
class StaticDemo {
public static void main(String args[]) {
System.out.println(Demo.a);
Demo.staticMethod(5);
Demo d = new Demo();
System.out.println(d.a);
d.staticMethod(0);
Demo e = new Demo();
System.out.println(e.a);
d.a += 3;
System.out.println(Demo.a+", " +d.a +", " +e.a);
}
}
The value of a final variable can no longer be modified once its value has been set. For
example,
final int data = 10;
Coding Guidelines:
Order of typing the final and public keyword may be interchanged.
Having this statement will cause a compilation error to occur since MyClass can no longer
be extended.
class OuterClass {
int data = 5;
class InnerClass {
int data2 = 10;
void method() {
System.out.println(data);
System.out.println(data2);
}
}
public static void main(String args[]) {
OuterClass oc = new OuterClass();
InnerClass ic = oc.new InnerClass();
System.out.println(oc.data);
System.out.println(ic.data2);
ic.method();
}
}
To be able to access the members of the inner class, we need an instance of the inner
class. Methods of the inner class can directly access members of the outer class.
2.1 Objectives
Basic exception handling has been introduced to you in your first programming course.
This lesson provides a deeper understanding of exceptions and also introduces assertions
as well.
Exceptions are short for exceptional events. These are simply errors that occur during
runtime, causing the normal program flow to be disrupted. There are different type of
errors that can occur. Some examples are divide by zero errors, accessing the elements
of an array beyond its range, invalid input, hard disk crash, opening a non-existent file
and heap memory exhausted.
The Exception class is refer to conditions that user programs can reasonably deal with.
These are usually the result of some flaws in the user program code. Example of
Exceptions are the division by zero error and the array out-of-bounds error.
The Error class, on the other hand, is used by the Java run-time system to handle errors
occurring in the run-time environment. These are generally beyond the control of user
programs since these are caused by the run-time environment. Examples include out of
memory errors and hard disk crash.
2.2.3 An Example
Consider the following program:
class DivByZero {
public static void main(String args[]) {
System.out.println(3/0);
System.out.println(“Pls. print me.”);
}
}
The message provides the information on the type of exception that has occurred and
the line of code where the exception had originated from. This is how the default handler
deals with uncaught exceptions. When no user code handles the occurring excpetion, the
default handler goes to work. It first prints out the description of the exception that
occured. Moreover, it also prints the stack trace that indicates the hierarchy of methods
where the exception happened. Lastly, the default handler causes the program to
terminate.
Now, what if you want to handle the exception in a different manner? Fortunately, the
Java programming language is incorporated with these three important keywords for
exception handling, the try, catch and finally keywords.
try {
<code to be monitored for exceptions>
} catch (<ExceptionType1> <ObjName>) {
<handler if ExceptionType1 occurs>
}
...
} catch (<ExceptionTypeN> <ObjName>) {
<handler if ExceptionTypeN occurs>
}
Coding Guidelines:
The catch block starts after the close curly brace of the preceding try or catch block.
Statements within the block are indented.
class DivByZero {
java.lang.ArithmeticException: / by zero
After exception.
A particular code monitored in the try block may cause more than one type of exception
to occur. In this case, the different types of errors can be handled using several catch
blocks. Note that the code in the try block may only throw one exception at a time but
may cause different types of exceptions to occur at different times.
Here is an example of a code that handles more than one type of exception.
class MultipleCatch {
public static void main(String args[]) {
try {
int den = Integer.parseInt(args[0]); //line 4
System.out.println(3/den); //line 5
} catch (ArithmeticException exc) {
System.out.println(“Divisor was 0.”);
} catch (ArrayIndexOutOfBoundsException exc2) {
System.out.println(“Missing argument.”);
}
System.out.println(“After exception.”);
}
}
Study what happens to the program when the following arguments are entered by the
user:
a) No argument
b) 1
c) 0
After exception.
class NestedTryDemo {
public static void main(String args[]){
try {
int a = Integer.parseInt(args[0]);
try {
int b = Integer.parseInt(args[1]);
System.out.println(a/b);
} catch (ArithmeticException e) {
System.out.println(“Divide by zero error!");
}
} catch (ArrayIndexOutOfBoundsException exc) {
System.out.println(“2 parameters are required!");
}
}
}
Analyze what happens to the code when these arguments are passed to the program:
a) No argument
b) 15
c) 15 3
d) 15 0
Here are the expected output for each sample argument set:
a) No argument
2 parameters are required!
b) 15
2 parameters are required!
c) 15 3
5
d) 15 0
Divide by zero error!
The code below has a nested try in disguise with the use of methods.
class NestedTryDemo2 {
static void nestedTry(String args[]) {
try {
int a = Integer.parseInt(args[0]);
int b = Integer.parseInt(args[1]);
System.out.println(a/b);
} catch (ArithmeticException e) {
System.out.println("Divide by zero error!");
}
}
public static void main(String args[]){
try {
nestedTry(args);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("2 parameters are required!");
}
}
What is the output of this program when tested on the following arguments?
a) No argument
b) 15
c) 15 3
d) 15 0
try {
<code to be monitored for exceptions>
} catch (<ExceptionType1> <ObjName>) {
<handler if ExceptionType1 occurs>
} ...
} finally {
<code to be executed before the try block ends>
}
Coding Guidelines:
Again, same coding convention applies to the finally block as in the catch block. It starts
after the close curly brace of the preceding catch block.Statements within this block are
also indented.
The finally block contains the code for cleaning up after a try or a catch. This block of
code is always executed regardless of whether an exception is thrown or not in the try
block. This remains true even if return, continue or break are executed. Four different
scenarios are possible in a try-catch-finally block. First, a forced exit occurs when the
program control is forced to skip out of the try block using a return, a continue or a
break statement. Second, a normal completion happens when the the try-catch-finally
statement executes normally without any error occurring. Third, the program code may
have specified in a particular catch block the exception that was thrown. This is called
the caught exception thrown scenario. Last, the opposite of the third scenario is the
uncaught exception thrown. In this case, the exception thrown was not specified in any
catch block. These scenarios are seen in the following code.
class FinallyDemo {
static void myMethod(int n) throws Exception{
try {
switch(n) {
case 1: System.out.println("first case");
return;
case 3: System.out.println("third case");
throw new RuntimeException("third case
demo");
case 4: System.out.println("fourth case");
throw new Exception("fourth case demo");
case 2: System.out.println("second case");
}
} catch (RuntimeException e) {
System.out.print("RuntimeException caught: ");
System.out.println(e.getMessage());
} finally {
System.out.println("try-block is entered.");
}
}
public static void main(String args[]){
for (int i=1; i<=4; i++) {
try {
FinallyDemo.myMethod(i);
} catch (Exception e){
System.out.print("Exception caught: ");
System.out.println(e.getMessage());
}
System.out.println();
}
}
}
first case
try-block is entered.
second case
try-block is entered.
third case
RuntimeException caught: third case demo
try-block is entered.
fourth case
try-block is entered.
Exception caught: fourth case demo
A method is required to either catch or list all exceptions it might throw, but it may omit
those of type Error or RuntimeException, or their subclasses.
class ThrowingClass {
static void myMethod() throws ClassNotFoundException {
throw new ClassNotFoundException ("just a demo");
}
}
class ThrowsDemo {
public static void main(String args[]) {
try {
ThrowingClass.myMethod();
} catch (ClassNotFoundException e) {
System.out.println(e);
}
}
}
Now that you’re quite familiar with several exception classes, it is time to introduce to
this rule: Multiple catches should be ordered from subclass to superclass.
class MultipleCatchError {
Compiling the code would produce this error message since the Exception class is a
superclass of the ArrayIndexOutOfBoundsException class.
MultipleCatchError.java:9: exception
java.lang.ArrayIndexOutOfBoundsException has already been caught
} catch (ArrayIndexOutOfBoundsException e2) {
A checked exceptions is just an exception that is checked by Java compiler. The compiler
makes sure that the program either catches or lists the occurring exception in the throws
clause. If the checked exception is neither caught nor listed, then a compiler error will
occur.
For creating your own exception, you’ll just have to create a class that extends the
RuntimeException (or Exception) class. Then, it is up to you to customize the class
according to the problem you are solving. Members and constructors may be added to
your exception class.
Here is an example.
class TestHateString {
public static void main(String args[]) {
2.6 Assertions
2.6.1 What are Assertions?
Assertions allow the programmer to find out if an assumption was met. For example, a
date with a month whose range is not between 1 and 12 should be considered as invalid.
The programmer may assert that the month should lie between this range. Although it is
possible to use other constructs to simulate the functionaly of assertions, it would be
hard to do this in such a way that the assertion feature could be disabled. The nice thing
about assertions is that the user has the option to turn it off or on at runtime.
To compile files that use assertions, an extra command line parameter is required as
shown below.
javac –source 1.4 MyProgram.java
If you want to run the program without the assertion feature, just run the program
normally.
java MyProgram
However, if you want to enable assertions, you need to use the –enableassertions or –ea
switch.
java –enableassertions MyProgram
To enable runtime assertion checking in NetBeans IDE, simply follow these steps:
1. Look for the project name in the Projects panel on the left. Right click on the
project name or icon.
2. Select Properties. This is the last option of the drop-down menu.
3. Click on Run from the Categories panel on the left.
4. Enter -ea for VM Options text field.
5. Click on OK button.
6. Compile and run the program as usual.
The following screen shots will help you understand the given steps:
The other form uses two expressions and the syntax for this format is shown below.
assert <expression1> : <expression2>;
where <expression1> is the condition that is asserted to be true and <expression2> is
some information helpful in diagnosing why the statement failed.
class AgeAssert {
public static void main(String args[]) {
int age = Integer.parseInt(args[0]);
assert(age>0);
/* if age is valid (i.e., age>0) */
if (age >= 18) {
System.out.println(“Congrats! You're an adult! =)”);
}
}
}
This code throws an AssertionError when the passed argument, i.e., args[0], has an
integer value less than 1 since the code asserts that age should be greater than 0. In
this case, the following error message is displayed at runtime.
Passing an argument value that is greater than 0 but less than 18 causes the program to
display no output.
For an argument value at least equal to 18, the following is the expected output:
The succeeding code is similar to the previous example except that is gives additional
information on the exception that has occurred. This uses the second assert syntax.
class AgeAssert {
public static void main(String args[]) {
int age = Integer.parseInt(args[0]);
assert(age>0) : "age should at least be 1";
/* if age is valid (i.e., age>0) */
if (age >= 18) {
System.out.println(“Congrats! You're an adult! =)”);
}
}
}
When the user inputs an argument less than 1, an AssertionError occurs and additional
information on the exception is displayed. For this scenario, the following output is
displayed.
For the other cases, this program gives similar output to the previous example.
2.7 Exercises
2.7.1 Hexadecimal to Decimal
Given a hexadecimal number as input. Convert this number to its decimal equivalent.
Define your own exception class and handle the case wherein the user inputs an invalid
hexadecimal number.
3.1 Objectives
This module introduces some advanced programming techniques. You will learn about
recursion and abstract data types in this section.
3.2 Recursion
3.2.1 What is Recursion?
Recursion is a powerful problem-solving technique that can be applied when the nature
of the problem is repetitive. Indeed, this type of problems are solvable using iteration
(i.e., using looping constructs such as for, while and do-while). In fact, iteration is a
more efficient tool compared to recursion but recursion provides a more elegant solution
to the problem. In recursion, methods are allowed to call upon itself. The data passed
into the method as arguments are stored temporarily onto a stack until calls to the
method have been completed.
Handling problems with repetitive nature using iteration requires explicit use of
repetition control structures. Meanwhile, for recursion, the task is repeated by calling a
method repetitively. The idea here is to define the problem in terms of smaller instances
of itself. Consider computing for the factorial of a given integer. It’s recursive definition
can be described as follows: factorial(n) = factorial(n-1) * n; factorial(1) = 1. For
example, the factorial of 2 is equal to the factorial(1)*2, which in turn is equal to 2. The
factorial of 3 is 6, which is equal to the factorial(2)*3.
With iteration, the process terminates when the loop condition fails. In the case of using
recursion, the process ends once a particular condition called the base case is satisfied.
The base case is simply the smallest instance of the problem. For example, as seen in
the recursive definition of factorial, the simplest case is when the input is 1. 1 for this
problem is the base case.
The use of iteration and recursion can both lead to infinite loops if these are not used
correctly.
Choosing between iteration and recursion is a matter of balancing good performance and
good software engineering.
Here is the equivalent code that uses the recursion tool instead.
class FactorialRecur {
static int factorial(int n) {
if (n == 1) { /* The base case */
return 1;
}
/* Recursive definition; Self-invocation */
return factorial(n-1)*n;
}
public static void main(String args[]) {
int n = Integer.parseInt(args[0]);
System.out.println(factorial(n));
}
}
Consider the expected output of the given codes for some integers. Trace what happens
in the code for some input. Here are some sample integers with their corresponding
output.
a) Input: 1
1
b) Input: 3
6
c) Input: 5
120
Here is another example. The input decimal is 165 to be converted to base 16.
class DecToOthers {
public static void main(String args[]) {
int num = Integer.parseInt(args[0]);
int base = Integer.parseInt(args[1]);
printBase(num, base);
}
static void printBase(int num, int base) {
int rem = 1;
String digits = "0123456789abcdef";
String result = "";
/* the iterative step */
while (num!=0) {
rem = num%base;
num = num/base;
result = result.concat(digits.charAt(rem)+"");
}
/* printing the reverse of the result */
for(int i = result.length()-1; i >= 0; i--) {
System.out.print(result.charAt(i));
}
}
}
To gain a better understanding of the code, trace it for a set of input. Here are some
sample input.
a) Num: 10, base: 2
1010
b) Num: 100, base: 8
144
c) Num: 200, base: 9
242
3.3.2 Stacks
A stack is a set of data elements wherein manipulation of the elements is allowed only at
the top of the stack. It is a linearly ordered collection of data on which the discipline of
“last in, first out” (LIFO) is imposed. Stacks are useful for a variety of applications such
as pattern recognition and conversion among infix, postfix and prefix notations.
The two operations associated with stacks are the push and pop operations. Push simply
means inserting at the top of the stack whereas pop refers to removing the element at
the top of the stack. To understand how the stack works, imagine how you would add or
remove a plate from a stack of plates. Your instinct would tell you to add or remove only
at the top of the stack because otherwise, there is a danger of causing the stack of plates
to fall.
n-1
...
6
5 Jayz top
4 KC
3 Jojo
2 Toto
1 Kyla
0 DMX bottom
Table 3: Stack illustration
The stack is full if the top reaches the cell labeled n-1. If the top is equal to -1, this
indicates that the stack is empty.
3.3.3 Queues
The queue is another example of an ADT. It is a linearly ordered collection of elements
which follow the discipline of “first-in, first-out”. Its applications include job scheduling in
operating system, topological sorting and graph traversal.
Enqueue and dequeue are the operations associated with queues. Enqueue refers to
inserting at the end of the queue whereas dequeue means removing front element of the
queue. To remember how a queue works, think of the queue’s literal meaning – a line.
Imagine yourself lining up to get the chance meeting your favorite star up close. If a new
person would like to join the line, this person would have to go to the end of the line.
Otherwise, there would probably be some fight. This is how enqueue works. Who gets to
meet his/her favorite star first among those who are waiting in the line? It should have
been the first person in the line. This person gets to leave the line first. Relate this to
how dequeue works.
0 1 2 3 4 5 6 7 8 9 ... n-1
Eve Jayz KC Jojo Toto Kyla DMX
front end ← Insert
→ Delete
Table 4: Queue illustration
The queue is empty if end is less than front. Meanwhile, it is full when the end is equal to
n-1.
The linked list is a dynamic structure as opposed to the array, which is a static structure.
This means that the linked list can grow and shrink in size depending on the need of the
user. A linked list is defined as a collection of nodes, each of which consists of some data
and a link or a pointer to the next node in the list.
Here is how the node class is implemented. This class can be used to create linked lists.
class Node {
int data; /* integer data contained in the node */
Node nextNode; /* the next node in the list */
}
class TestNode {
public static void main(String args[]) {
Node emptyList = null; /* create an empty list */
/* head points to 1st node in the list */
Node head = new Node();
/* initialize 1st node in the list */
head.data = 5;
head.nextNode = new Node();
head.nextNode.data = 10;
/* null marks the end of the list */
head.nextNode.nextNode = null;
/* print elements of the list */
Node currNode = head;
while (currNode != null) {
System.out.println(currNode.data);
currNode = currNode.nextNode;
}
}
}
class DynamicIntStack{
private IntStackNode top; /* head or top of the stack */
class IntStackNode { /* node class */
int data;
IntStackNode next;
IntStackNode(int n) {
data = n;
next = null;
}
}
void push(int n){
/* no need to check for overflow */
IntStackNode node = new IntStackNode(n);
node.next = top;
top = node;
}
int pop() {
if (isEmpty()) {
return -1;
/* may throw a user-defined exception */
} else {
int n = top.data;
top = top.next;
return n;
}
}
boolean isEmpty(){
return top == null;
}
public static void main(String args[]) {
DynamicIntStack myStack = new DynamicIntStack();
myStack.push(5);
myStack.push(10);
/* print elements of the stack */
IntStackNode currNode = myStack.top;
while (currNode!=null) {
System.out.println(currNode.data);
currNode = currNode.next;
}
System.out.println(myStack.pop());
System.out.println(myStack.pop());
}
}
You've now been introduced to the foundations of abstract data types. In particular,
you've learned about the basics of linked lists, stacks and queues. A good news is these
abstract data types have already been implemented and included in Java. The Stack and
LinkedList classes are available for use without a full understanding of these concepts.
However, as computer scientists, it is important that we understand the abstract data
types. Thus, a detailed explanation was still given in the preceding section. With the
release of J2SE5.0, the Queue interface was also made available. For the details on these
classes and interface, please refer to the Java API documentation.
Java has provided us with other Collection classes and interfaces, which are all found in
the java.util package. Examples of Collection classes include LinkedList, ArrayList,
HashSet and TreeSet. These classes are actually implementations of different collection
interfaces. At the root of the collection interface hierarchy is the Collection interface. A
collection is just a group of objects that are known as its elements. Collections may allow
duplicates and requires no specific ordering.
The SDK does not provide any built-in implementations of this interface but direct
subinterfaces, the Set interface and the List interface, are available. Now, what is the
difference between these two interfaces. A set is an unordered collection that contains no
duplicates. Meanwhile, a list is an ordered collection of elements where duplicates are
permitted. HashSet, LinkedHashSet and TreeSet are some known implementing classes
of the interface Set. ArrayList, LinkedList and Vector are some of the classes
implementing the interface List.
<root interface>
Collection
<interface> <interface>
Set List
<implementing classes> <implementing classes>
HashSet LinkedHashSet TreeSet ArrayList LinkedList Vector
Table 5: Java collections
The following is a list of some of the Collection methods provided in the Collections API of
Java 2 Platform SE v1.4.1. In Java 2 Platform SE v.1.5.0, these methods were modified
to accomodate generic types. Since generic types have not been discussed yet, it is
advisable to consider these methods first. It is advised that you refer to newer Collection
methods once you understand the generic types, which is discussed in a latter chapter.
Collection Methods
public boolean add(Object o)
Inserts the Object o to this collection. Returns true if o was successfully added to the
collection.
public void clear()
Removes all elements of this collection.
public boolean remove(Object o)
Removes a single instance of the Object o from this collection, if it is present. Returns
true if o was found and removed from the collection.
public boolean contains(Object o)
Returns true if this collection contains the Object o.
public boolean isEmpty()
Returns true if this collection does not contain any object or element.
Please refer to the API documentation for a complete list of the methods found in the
Collection, List and Set interface.
We’ll now look at some collection classes. Please refer to the API for the list of methods
included in these classes.
In a preceding section, you’ve seen how to implement a linked list on your own. The Java
SDK also has provided us with a built-in implementation of the linked list. The LinkedList
class contains methods that allows linked lists to be used as stacks, queues or some
other ADT. The following code shows how to use the LinkedList class.
import java.util.*;
class LinkedListDemo {
public static void main(String args[]) {
LinkedList list = new LinkedList();
list.add(new Integer(1));
list.add(new Integer(2));
list.add(new Integer(3));
list.add(new Integer(1));
System.out.println(list + ", size = " + list.size());
list.addFirst(new Integer(0));
list.addLast(new Integer(4));
System.out.println(list);
System.out.println(list.getFirst() + ", " +
list.getLast());
System.out.println(list.get(2) + ", " + list.get(3));
list.removeFirst();
list.removeLast();
System.out.println(list);
list.remove(new Integer(1));
System.out.println(list);
list.remove(3);
System.out.println(list);
list.set(2, "one");
System.out.println(list);
}
}
The ArrayList is a resizable version an ordinary array. It implements the List interface.
Analyze the following code.
import java.util.*;
class ArrayListDemo {
public static void main(String args[]) {
ArrayList al = new ArrayList(2);
import java.util.*;
class HashSetDemo {
public static void main(String args[]) {
HashSet hs = new HashSet(5, 0.5f);
System.out.println(hs.add("one"));
System.out.println(hs.add("two"));
System.out.println(hs.add("one"));
System.out.println(hs.add("three"));
System.out.println(hs.add("four"));
System.out.println(hs.add("five"));
System.out.println(hs);
}
}
The TreeSet is an implementation of the Set interface that uses a tree. This class ensures
that the sorted set will be arranged in ascending order. Consider how the TreeSet class
was used in the following source code.
import java.util.*;
class TreeSetDemo {
public static void main(String args[]) {
TreeSet ts = new TreeSet();
ts.add("one");
ts.add("two");
ts.add("three");
ts.add("four");
System.out.println(ts);
}
}
4.1 Objectives
Java comes in with many built-in classes that you may find useful. Let's explore these
classes.
Math Methods
public static double abs(double a)
Returns the positive value of the parameter. An overloaded method. Can also take in
a float or an integer or a long integer as a parameter, in which case the return type is
either a float or an integer or a long integer, respectively.
public static double random()
Returns a random postive value greater than or equal to 0.0 but less than 1.0.
public static double max(double a, double b)
Returns the larger value between two double values, a and b. An overloaded method.
Can also take in float or integer or long integer values as parameters, in which case
the return type is either a float or an integer or a long integer, respectively.
public static double min(double a, double b)
Returns the smaller value between two double values, a and b. An overloaded
method. Can also take in float or integer or long integer values as parameters, in
which case the return type is either a float or an integer or a long integer,
respectively.
public static double ceil(double a)
Returns the smallest integer greater than or equal to the specified parameter a.
public static double floor(double a)
Returns the largest integer that is lesser than or equal to the specified parameter a.
public static double exp(double a)
Returns Euler's number e raised to the power of the passed argument a.
public static double log(double a)
Returns the natural logarithm (base e) of a, the double value parameter.
public static double pow(double a, double b)
Returns the double value of a raised to the double value of b.
public static long round(double a)
Returns the nearest long to the given argument. An overloaded method. Can also take
in a float as an argument and returns the nearest int in this case.
public static double sqrt(double a)
Returns the square root of the argument a.
public static double sin(double a)
Returns the trigonometric sine of the given angle a.
public static double toDegrees(double angrad)
Returns the degree value approximately equivalent to the given radian value.
public static double toRadians(double angdeg)
Returns the radian value approximately equivalent to the given degree value.
Table 7: Some methods of class Math
class MathDemo {
public static void main(String args[]) {
System.out.println("absolute value of -5: " +
Math.abs(-5));
System.out.println("absolute value of 5: " +
Math.abs(-5));
System.out.println("random number(max value is 10): " +
Math.random()*10);
System.out.println("max of 3.5 and 1.2: " +
Math.max(3.5, 1.2));
System.out.println("min of 3.5 and 1.2: " +
Math.min(3.5, 1.2));
System.out.println("ceiling of 3.5: " + Math.ceil(3.5));
System.out.println("floor of 3.5: " + Math.floor(3.5));
System.out.println("e raised to 1: " + Math.exp(1));
System.out.println("log 10: " + Math.log(10));
System.out.println("10 raised to 3: " + Math.pow(10,3));
System.out.println("rounded off value of pi: " +
Math.round(Math.PI));
System.out.println("square root of 5 = " + Math.sqrt(5));
System.out.println("10 radian = " + Math.toDegrees(10) +
" degrees");
System.out.println("sin(90): " +
Math.sin(Math.toRadians(90)));
}
}
Here is a sample output of the given program. Try running the program yourself and feel
free to experiment with the given arguments.
String Methods
public char charAt(int index)
Returns the character located in the specified index.
public int compareTo(String anotherString)
Compares this string with the specified parameter. Returns a negative value if this
string comes lexicographically before the other string, 0 if both of the strings have the
same value and a postive value if this string comes after the other string
lexicographically.
public int compareToIgnoreCase(String str)
Like compareTo but ignores the case used in this string and the specified string.
String Methods
public boolean equals(Object anObject)
Returns true if this string has the same sequence of characters as that of the Object
specified, which should be a String object. Otherwise, if the specified parameter is not a
String object or if it doesn't match the sequence of symbols in this string, the method
will return false.
public boolean equalsIgnoreCase(String anotherString)
Like equals but ignores the case used in this string and the specified string.
public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
Gets the characters from this string starting at the srcBegin index up to the srcEnd
index and copies these characters to the dst array starting at the dstBegin index.
public int length()
Returns the length of this string.
public String replace(char oldChar, char newChar)
Returns the string wherein all occurrences of the oldChar in this string is replaced with
newChar.
public String substring(int beginIndex, int endIndex)
Returns the substring of this string starting at the specified beginIndex index up to the
endIndex index.
public char[] toCharArray()
Returns the character array equivalent of this string.
public String trim()
Returns a modified copy of this string wherein the leading and trailing white space are
removed.
public static String valueOf(-)
Takes in a simple data type such as boolean, integer or character, or it takes in an
object as a parameter and returns the String equivalent of the specified parameter.
Table 8: Some methods of class String
class StringDemo {
public static void main(String args[]) {
String name = "Jonathan";
System.out.println("name: " + name);
System.out.println("3rd character of name: " +
name.charAt(2));
/* character that first appears alphabetically has lower
unicode value */
System.out.println("Jonathan compared to Solomon: " +
name.compareTo("Solomon"));
System.out.println("Solomon compared to Jonathan: " +
"Solomon".compareTo("Jonathan"));
/* 'J' has lower unicode value compared to 'j' */
System.out.println("Jonathan compared to jonathan: " +
name.compareTo("jonathan"));
System.out.println("Jonathan compared to jonathan (ignore
name: Jonathan
3rd character of name: n
Jonathan compared to Solomon: -9
Solomon compared to Jonathan: 9
Jonathan compared to jonathan: -32
Jonathan compared to jonathan (ignore case): 0
Is Jonathan equal to Jonathan? true
Is Jonathan equal to jonathan? false
Is Jonathan equal to jonathan (ignore case)? true
content of charArr after getChars method: Hi Jo
Length of name: 8
Replace a's with e's in name: Jonethen
A substring of name: Jo
Trim " a b c d e f ": "a b c d e f"
String representation of boolean expression 10>10: false
String representation of boolean expression 10<10: false
name: Jonathan
Here are some of the methods in the StringBuffer class. Please refer to the Java API
documentation.
StringBuffer Methods
public int capacity()
Returns the current capacity of this StringBuffer object.
public StringBuffer append(-)
Appends the string representation of the argument to this StringBuffer object. Takes in
a single parameter which may be of these data types: boolean, char, char [], double,
float, int, long, Object, String and StringBuffer. Still has another overloaded version.
public char charAt(int index)
Returns the character located in the specified index.
public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
Gets the characters from this object starting at the srcBegin index up to the srcEnd
index and copies these characters to the dst array starting at the dstBegin index.
public StringBuffer delete(int start, int end)
Deletes the characters within the specified range.
public StringBuffer insert(int offset, -)
Inserts the string representation of the second argument at the specified offset. An
overloaded method. Possible data types for the second argument: boolean, char, char
[], double, float, int, long, Object and String. Still has another overloaded version.
public int length()
Returns the number of characters in this StringBuffer object.
public StringBuffer replace(int start, int end, String str)
Replaces part of this object, as specified by the first two arguments, with the specified
string str.
public String substring(int start, int end)
Returns the substring of this string starting at the specified start index up to the end
index.
public String toString()
Converts this object to its string representation.
Table 9: Some methods of class StringBuffer
class StringBufferDemo {
public static void main(String args[]) {
StringBuffer sb = new StringBuffer("Jonathan");
System.out.println("sb = " + sb);
/* initial capacity is 16 */
System.out.println("capacity of sb: " + sb.capacity());
System.out.println("append \'O\' to sb: " +
sb.append("O"));
System.out.println("sb = " + sb);
System.out.println("3rd character of sb: " +
sb.charAt(2));
char charArr[] = "Hi XX".toCharArray();
/* Need to add 1 to the endSrc index of getChars */
sb.getChars(0, 2, charArr, 3);
System.out.print("getChars method: ");
System.out.println(charArr);
System.out.println("Insert \'jo\' at the 3rd cell: " +
sb.insert(2, "jo"));
System.out.println("Delete \'jo\' at the 3rd cell: " +
sb.delete(2,4));
System.out.println("length of sb: " + sb.length());
System.out.println("replace: " +
sb.replace(3, 9, " Ong"));
/* Need to add 1 to the endIndex parameter of substring*/
System.out.println("substring (1st two characters): " +
sb.substring(0, 3));
System.out.println("implicit toString(): " + sb);
}
}
Here's the output of the given program. Again, feel free to experiment with the code
since the best way to learn these syntax is through actual use.
sb = Jonathan
capacity of sb: 24
append 'O' to sb: JonathanO
sb = JonathanO
3rd character of sb: n
getChars method: Hi Jo
Insert 'jo' at the 3rd cell: JojonathanO
Delete 'jo' at the 3rd cell: JonathanO
length of sb: 9
replace: Jon Ong
substring (1st two characters): Jon
implicit toString(): Jon Ong
The names of the different wrapper classes are quite easy to remember since they are
very similar to the primitive data types. Also, note that the wrapper classes are just
capitalized and spelled out versions of the primitive data types.
class BooleanWrapper {
public static void main(String args[]) {
boolean booleanVar = 1>2;
Boolean booleanObj = new Boolean("TRue");
/* primitive to object; can also use valueOf method */
Boolean booleanObj2 = new Boolean(booleanVar);
System.out.println("booleanVar = " + booleanVar);
System.out.println("booleanObj = " + booleanObj);
System.out.println("booleanObj2 = " + booleanObj2);
System.out.println("compare 2 wrapper objects: " +
booleanObj.equals(booleanObj2));
/* object to primitive */
booleanVar = booleanObj.booleanValue();
System.out.println("booleanVar = " + booleanVar);
}
}
booleanVar = false
booleanObj = true
booleanObj2 = false
compare 2 wrapper objects: false
booleanVar = true
Process Methods
public abstract void destroy()
Kills the current process.
public abstract int waitFor() throws InterruptedException
Does not exit until this process terminates.
Table 11: Some methods of class Process
Runtime Methods
public static Runtime getRuntime()
Returns the runtime environment associated with the current Java application.
public Process exec(String command) throws IOException
Causes the specified command to be executed. Allows you to execute new processes.
Table 12: Some methods of class RunTime
class RuntimeDemo {
public static void main(String args[]) {
Runtime rt = Runtime.getRuntime();
Process proc;
try {
proc = rt.exec("regedit");
proc.waitFor(); //try removing this line
} catch (Exception e) {
System.out.println("regedit is an unknown command.");
}
}
}
System Methods
public static void arraycopy(Object src, int srcPos, Object dest, int
destPos, int length)
Copies length items from the source array src starting at srcPos to dest starting at index
destPos. Faster than manually programming the code for this yourself.
public static long currentTimeMillis()
Returns the difference between the current time and January 1, 1970 UTC. Time
returned is measured in milliseconds.
public static void exit(int status)
Kills the Java Virtual Machine (JVM) running currently. A non-zero value for status by
convention indicates an abnormal exit.
public static void gc()
Runs the garbage collector, which reclaims unused memory space for recycling.
public static void setIn(InputStream in)
Changes the stream associated with System.in, which by default refers to the keyboard.
public static void setOut(PrintStream out)
Changes the stream associated with System.out, which by default refers to the console.
import java.io.*;
class SystemDemo {
public static void main(String args[]) throws IOException {
int arr1[] = new int[5000000];
int arr2[] = new int[5000000];
long startTime, endTime;
/* initialize arr1 */
for (int i = 0; i < arr1.length; i++) {
arr1[i] = i + 1;
}
/* copying manually */
startTime = System.currentTimeMillis();
for (int i = 0; i < arr1.length; i++) {
arr2[i] = arr1[i];
}
endTime = System.currentTimeMillis();
System.out.println("Time for manual copy: " +
(endTime-startTime) + " ms.");
/* using the copy utility provided by java – the
arraycopy method */
startTime = System.currentTimeMillis();
System.arraycopy(arr1, 0, arr2, 0, arr1.length);
endTime = System.currentTimeMillis();
System.out.println("Time w/the use of arraycopy: " +
(endTime-startTime) + " ms.");
System.gc(); //force garbage collector to work
System.setIn(new FileInputStream("temp.txt"));
/* in NetBeans, temp.txt should be located
in the project folder */
System.exit(0);
}
}
The program gives varying output. It may generate the following sample output:
5 Text-Based Applications
5.1 Objectives
In this lesson, a review on using command-line arguments is found in this section.
Moreover, you will learn more about using streams to get input from the user during
runtime and to manipulate files.
After completing this lesson, you should be able to:
1. Get input from the command-line
2. Explain how to manipulate system properties
2. Read from the standard input
4. Read and write to files
java Calculate 1 2
In this example, the data 1 is stored in the variable args[0] whereas the data 2 is stored
in args[1]. With this, the purpose of declaring String args[] as a parameter in the main
method becomes clear.
If you're using NetBeans, here are the steps for passing command-line arguments.
1. Look for the project name in the Projects panel on the left. Right click on the
project name or icon.
2. Select Properties. This is the last option of the drop-down menu.
3. Click on Run from the Categories panel on the left.
4. Enter the arguments separated by space for Arguments text field.
5. Click on OK button.
6. Compile and run the program as usual.
To understand these steps more easily, the following screen shots are provided:
Besides passing arguments to the main method, you can also manipulate system
properties from the command line.
System properties are quite similar to environment variables but the former not being
platform-dependent. A property is simply a mapping between the property name to its
corresponding value. This is represented in Java with the Properties class. The System
class provides a methods for determining the current system properties, the
getProperties method that returns a Properties object. The same class also provides for
the getProperty method that has two forms.
You can use the -D option with the java command from the command-line to include a
new property.
java -D<name>=value
For example, to set the system property user.home to have a value of philippines, use
the following command:
java -Duser.home=philippines
To display the list of system properties available in your system and their corresponding
values, you can use the getProperties method as follows:
System.getProperties().list(System.out);
-- listing properties --
java.runtime.name=Java(TM) 2 Runtime Environment, Stand...
sun.boot.library.path=C:\Program Files\Java\jdk1.5.0_06\jre...
java.vm.version=1.5.0_06-b05
java.vm.vendor=Sun Microsystems Inc.
java.vendor.url=http://java.sun.com/
path.separator=;
java.vm.name=Java HotSpot(TM) Client VM
file.encoding.pkg=sun.io
user.country=US
sun.os.patch.level=Service Pack 2
java.vm.specification.name=Java Virtual Machine Specification
user.dir=C:\Documents and Settings\becca\Neste...
java.runtime.version=1.5.0_06-b05
java.awt.graphicsenv=sun.awt.Win32GraphicsEnvironment
java.endorsed.dirs=C:\Program Files\Java\jdk1.5.0_06\jre...
os.arch=x86
java.io.tmpdir=C:\DOCUME~1\becca\LOCALS~1\Temp\
line.separator=
To read characters from the keyboard, you can use the System.in byte stream warped in
a BufferedReader object. The following line shows how to do this:
The read method of the BufferedReader object is then used to read from the input
device.
import java.io.*;
class FavoriteCharacter {
public static void main(String args[]) throws IOException {
System.out.println("Hi, what's your favorite
character?");
char favChar;
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));
favChar = (char) br.read();
System.out.println(favChar + " is a good choice!");
}
}
Running this code with the character a as input generates the following output:
If you prefer reading an entire line instead of reading one character at a time, you can
use the readLine method.
str = br.readLine();
Here is a program almost similar to the preceding example but reads an entire string
instead of just one character.
import java.io.*;
class GreetUser {
public static void main(String args[]) throws IOException {
System.out.println("Hi, what's your name?");
String name;
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));
name = br.readLine();
System.out.println("Nice to meet you, " + name + "! :)");
}
}
Here is the expected output of GreetUser when the user inputs rebecca:
When using streams, don't forget to import the java.io package as shown below:
import java.io.*;
One more reminder, reading from streams may cause checked exceptions to occur. Don't
forget to handle these exceptions using try-catch statements or by indicating the
FileInputStream(String filename)
After creating an input stream, you can now use the stream to read from the associated
file using the read method. The read method returns an integer and it returns -1 when
the end of the file is reached.
Here is an example.
import java.io.*;
class ReadFile {
public static void main(String args[]) throws IOException {
System.out.println("What is the name of the file to read
from?");
String filename;
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));
filename = br.readLine();
System.out.println("Now reading from " + filename +
"...");
FileInputStream fis = null;
try {
fis = new FileInputStream(filename);
} catch (FileNotFoundException ex) {
System.out.println("File not found.");
}
try {
char data;
int temp;
do {
temp = fis.read();
data = (char) temp;
if (temp != -1) {
System.out.print(data);
}
} while (temp != -1);
} catch (IOException ex) {
System.out.println("Problem in reading from the
file.");
}
}
}
Assuming temp.txt exists and it contains the text temporary file, here is a sample output
of this program:
FileOutputStream(String filename)
Once the output stream is created, you can now use the stream to write to the linked file
using the write method. The method has the following signature:
void write(int b)
The parameter b refers to the data to be written to the actual file associated to the
output stream.
import java.io.*;
class WriteFile {
public static void main(String args[]) throws IOException {
System.out.println("What is the name of the file to be
written to?");
String filename;
BufferedReader br = new BufferedReader(new
InputStreamReader(System.in));
filename = br.readLine();
System.out.println("Enter data to write to " + filename +
"...");
System.out.println("Type q$ to end.");
FileOutputStream fos = null;
try {
fos = new FileOutputStream(filename);
} catch (FileNotFoundException ex) {
System.out.println("File cannot be opened for
writing.");
}
try {
boolean done = false;
int data;
do {
data = br.read();
if ((char)data == 'q') {
data = br.read();
if ((char)data == '$') {
done = true;
} else {
fos.write('q');
fos.write(data);
}
} else {
fos.write(data);
}
} while (!done);
} catch (IOException ex) {
System.out.println("Problem in reading from the
file.");
}
}
}
5.5 Exercises
5.5.1 Spaces to Underscore
Create a program that takes in two strings as arguments – the source and destination
filenames, respectively. Then, read from the source file and write its content to the
destination file with all occurrences of spaces (' ') converted to underscores ('_').
Sample Run:
*
* *
* * *
* * * *
6 Sorting Algorithms
6.1 Objectives
Sorting is the task of arranging elements in a particular order and it is implemented in a
variety of applications. Consider a banking application, which displays the list of active
client accounts, for instance. Users of this system most probably prefer having the list in
an ascending order for convenience.
Several sorting algorithms have been invented because the task is so fundamental and
also frequently used. For these reasons, examining existing algorithms would be very
beneficial.
The insertion sort algorithm basically divides the data elements to be sorted into two
groups, the unsorted (analogous to the 1st table) and the sorted (analogous to the 2nd
table) sections. The first available element is selected from the unsorted section of the
array and it is properly positioned in the sorted section of the array. This step is repeated
until there are no more elements left in the unsorted part of the array.
6.2.2 An Example
At the end of this module, you will be asked to give your own Java implementation of the
different sorting algorithms discussed in this section.
Again, let us observe how this algorithm would work on a standard deck of cards.
Assume that the cards are to be arranged in ascending order. Initially, the set of cards
are arranged linearly on the table from left to right and top to bottom. Check the rank of
each card and select the card with the lowest rank. Exchange the position of this card
with the position of the first card on the upper left corner. Next, find the card with the
lowest rank among the remaining cards excluding the first chosen card. Swap the newly
selected card with the card in the second position. Repeat the same step until the second
to the last position on the table is challenged and may be swapped by a card with a
lower value.
The main idea behind the selection sort algorithm is to select the element with the
lowest value and then swap the chosen element with the element in the ith position. The
value of i starts from 1 to n, where n is the total number of elements minus 1.
6.3.2 An Example
1. Divide
Divide the main problem into subproblems.
2. Conquer
Conquer the subproblems by recursively solving them. In the case that the
suproblems are simple and small enough, a straightforward manner of solving them
would be better.
3. Combine
Combine the solutions to the suproblems, which would lead to the solution of the
main problem.
1. Divide
Divide the sequence of data elements into two halves.
2. Conquer
Conquer each half by recursively calling the Merge sort procedure.
3. Combine
Combine or merge the two halves recursively to come up with the sorted sequence.
Recursion stops when the base case is reached. This is the case wherein the half to be
sorted has exactly one element. Since only one element is left to be sorted, this half is
already arranged in its proper sequence.
6.4.4 An Example
Given:
7 2 5 6
Combine
2 7
Combine
5 6
6.5 Quicksort
Quicksort was invented by C.A.R. Hoare. Like merge sort, this algorithm is also based on
the divide-and-conquer paradigm. But instead of having three phases, it involves the
following phases only:
1. Divide
Partition the array into two subarrays A[p...q-1] and A[q+1...r] such that each
element in A[p...q-1] is less than or equal to A[q] and each element in A[q+1...r] is
greater than or equal to A[q]. A[q] is called the pivot. Computation of q is part of the
partitioning procedure.
2. Conquer
Sort the subarrays by recursively calling the quickSort method.
There is no longer any "Combine" phase since the subarrays are sorted in place.
6.5.2 An Example
Given array:
3 1 4 1 5 9 2 6 5 3 5 8
Initialize left to point to the second element and right to point to the last element.
left right
3 1 4 1 5 9 2 6 5 3 5 8
Move the left pointer to the right direction until we find a value larger than the pivot.
Move the right pointer to the left direction until we fina value not larger than the pivot.
left right
3 1 4 1 5 9 2 6 5 3 5 8
Swap elements.
left right
3 1 3 1 2 9 5 6 5 4 5 8
Observe that the left and right pointers have crossed such that right < left. In this case,
swap pivot with right.
pivot
2 1 3 1 3 9 5 6 5 4 5 8
Pivoting is now complete. Recursively sort subarrays on each side of the pivot.
7.1 Objectives
Without learning about graphical user interface (GUI) APIs, you would still be able to
create quite a descent range of different programs. However, your applications are very
likely to be bland and unappealing to the users. Having a good GUI affects the usage of
your application. This results in ease of use and enjoyment of use for the users of your
program. Java provides tools like Abstract Windowing Toolkit (AWT) and Swing to
develop interactive GUI applications.
Both AWT and Swing provides GUI components that can be used in creating Java
applications and applets. You will learn about applets in a latter section. Unlike some
AWT components that use native code, Swing is written entirely using the Java
programming language. As a result, Swing provides a platform-independent
implementation ensuring that applications deployed across different platforms have the
same appearance. AWT, however, does ensure that the look and feel of an application
run on two different machines be comparable. The Swing API is built around a number of
APIs that implement various parts of the AWT. As a result, AWT components can still be
used with Swing components.
To set the size of the window, the overloaded setSize method is used.
void setSize(int width, int height)
Resizes this component to the width and height provided as parameters.
void setSize(Dimension d)
Resizes this component to d.width and d.height based on the Dimension d specified.
A window by default is not visible unless you set its visibility to true. Here is the syntax
for the setVisible method.
void setVisible(boolean b)
In designing GUI applications, Frame objects are usually used. Here's an example of how
to create such an application.
import java.awt.*;
public class SampleFrame extends Frame {
public static void main(String args[]) {
SampleFrame sf = new SampleFrame();
sf.setSize(100, 100); //Try removing this line
sf.setVisible(true); //Try removing this line
}
}
Note that the close button of the frame doesn't work yet because no event handling
mechanism has been added to the program yet. You'll learn about event handling in the
next module.
7.3.2 Graphics
Several graphics method are found in the Graphics class. Here is the list of some of these
methods.
Related to this class is the Color class, which has three constructors.
Here is a sample program that uses some of the methods in the Graphics class.
import java.awt.*;
For a panel to become visible, it should be placed inside a visible window like a frame.
import java.awt.*;
1. FlowLayout
2. BorderLayout
3. GridLayout
4. GridBagLayout
5. CardLayout
6.
The layout manager can be set using the setLayout method of the Container class. The
method has the following signature.
If you prefer not to use any layout manager at all, you pass null as an argument to this
method. But then, you would have to position the elements manually with the use of the
setBounds method of the Component class.
The method controls the position based on the arguments x and y, and the size based on
the specified width and height. This would be quite difficult and tedious to program if you
have several Component objects within the Container object. You'll have to call this
method for each component.
In this section, you'll learn about the first three layout managers.
FlowLayout Constructors
FlowLayout()
Creates a new FlowLayout object with the center alignment and 5-unit horizontal and
vertical gap applied to the components by default.
FlowLayout(int align)
Creates a new FlowLayout object with the specified alignment and the default 5-unit
horizontal and vertical gap applied to the components.
FlowLayout(int align, int hgap, int vgap)
Creates a new FlowLayout object with the first argument as the alignment applied and
the hgap-unit horizontal and vgap-unit vertical gap applied to the components.
Table 19: FlowLayout constructors
The gap refers to the spacing between the components and is measured in pixels. The
import java.awt.*;
BorderLayout Constructors
BorderLayout()
Creates a new BorderLayout object with no spacing applied among the different
components.
BorderLayout(int hgap, int vgap)
Creates a new BorderLayout object with hgap-unit horizontal and vgap-unit spacing
applied among the different components.
Table 20: BorderLayout constructors
Like in the FlowLayout manager, the parameters hgap and vgap here also refers to the
spacing between the components within the container.
To add a component to a specified region, use the add method and pass two arguments:
the component to add and the region where the component is to be positioned. Note that
only one component can be placed in one region. Adding more than one component to a
particular container results in displaying only the last component added. The following
list gives the valid regions are predefined fields in the BorderLayout class.
1. BorderLayout.NORTH
2. BorderLayout.SOUTH
3. BorderLayout.EAST
4. BorderLayout.WEST
5. BorderLayout.CENTER
import java.awt.*;
Here is a sample output of this program. The second figure shows the effect of resizing
the frame.
GridLayout Constructors
GridLayout()
Creates a new GridLayout object with a single row and a single column by default.
GridLayout(int rows, int cols)
Creates a new GridLayout object with the specified number of rows and columns.
GridLayout(int rows, int cols, int hgap, int vgap)
Creates a new GridLayout object with the specified number of rows and columns. hgap-
unit horizontal and vgap-unit vertical spacings are applied to the components.
Table 21: GridLayout constructors
import java.awt.*;
This is the output of the program. Observe the effect of resizing the frame.
import java.awt.*;
The names of the Swing GUI components are almost similar to that of the AWT GUI
components. An obvious difference is in the naming conventions of the components.
Basically, the name of Swing components are just the name of AWT components but with
an additional prefix of J. For example, one component in AWT is the Button class. The
corresponding component for this in the Swing package is the JButton class. Provided
below is the list of some of the Swing GUI components.
Swing Description
Component
JComponent The root class for all Swing components, excluding top-level containers.
JButton A "push" button. Corresponds to the Button class in the AWT package.
JCheckBox An item that can be selected or deselected by the user. Corresponds to
the Checkbox class in the AWT package.
JFileChooser Allows user to select a file. Corresponds to the FileChooser class in the
AWT package.
JTextField Allows for editing of a single-line text. Corresponds to TextField class in
the AWT package.
JFrame Extends and corresponds to the Frame class in the AWT package but
the two are slightly incompatible in terms of adding components to this
container. Need to get the current content pane before adding a
component.
JPanel Extends JComponent. A simple container class but not top-level.
Corresponds to Panel class in the AWT package.
Swing Description
Component
JApplet Extends and corresponds to the Applet class in the AWT package. Also
slightly incompatible with the Applet class in terms of adding
components to this container.
JOptionPane Extends JComponent. Provides an easy way of displaying pop-up dialog
box.
JDialog Extends and corresponds to the Dialog class in the AWT package.
Usually used to inform the user of something or prompt the user for an
input.
JColorChooser Extends JComponent. Allow the user to select a color.
For the complete list of Swing components, please refer to the API documentation.
import javax.swing.*;
import java.awt.*;
class SwingDemo {
JFrame frame;
JPanel panel;
JTextField textField;
JButton button;
Container contentPane;
void launchFrame() {
/* initialization */
frame = new JFrame("My First Swing Application");
panel = new JPanel();
textField = new JTextField("Default text");
button = new JButton("Click me!");
contentPane = frame.getContentPane();
/* add components to panel– uses FlowLayout by default */
panel.add(textField);
panel.add(button);
/* add components to contentPane– uses BorderLayout */
contentPane.add(panel, BorderLayout.CENTER);
frame.pack();
//causes size of frame to be based on the components
frame.setVisible(true);
}
public static void main(String args[]) {
Note that the java.awt package is still imported because the layout managers in use are
defined in this package. Also, giving a title to the frame and packing the components
within the frame is applicable for AWT frames too.
Coding Guidelines:
Observe the coding style applied in this example as opposed to the examples for AWT.
The components are declared as fields, a launchFrame method is defined, and
initialization and addition of components are all done in the launchFrame method. We no
longer just extend the Frame class. The advantage of using this style would become
apparent when we get to event handling.
import javax.swing.*;
class JOptionPaneDemo {
JOptionPane optionPane;
void launchFrame() {
optionPane = new JOptionPane();
String name = optionPane.showInputDialog("Hi, what's your
name?");
optionPane.showMessageDialog(null,
"Nice to meet you, " + name + ".", "Greeting...",
optionPane.PLAIN_MESSAGE);
System.exit(0);
}
public static void main(String args[]) {
new JOptionPaneDemo().launchFrame();
}
}
8.1 Objectives
In this module, you will learn how to handle events triggered when the user interacts
with your GUI application. After completing this module, you'll be able to develop GUI
applications that responds to user interaction.
1. Event Source
The event source refers to the GUI component that generates the event. For example,
if the user presses a button, the event source in this case is the button.
2. Event Listener/Handler
The event listener receives news of events and processes user's interaction. When a
button is pressed, the listener may handle this by displaying an information useful to
the user.
3. Event Object
When an event occurs (i.e., when the user interacts with a GUI component), an event
object is created. The object contains all the necessary information about the event
that has occurred. The information includes the type of event that has occurred, say,
the mouse was clicked. There are several event classes for the different categories of
user action. An event object has a data type of one of these classes.
Initially, a listener should be registered with a source so that it can receive information
about events that occur at the source. Only registered listeners can receive notifications
of events. Once registered, a listener simply waits until an event occurs.
When something happens at the event source, an event object describing the event is
created. The event is then fired by the source to the registered listeners.
Once the listener receives an event object (i.e., a notification) from the source, it goes to
work. It deciphers the notification and processes the event that occurred.
<Type> depends on the type of event source. It can be Key, Mouse, Focus, Component,
Action and others.
Several listeners can register with one event source to receive event notifications.
Take note that all AWTEvent subclasses follow this naming convention:
<Type>Event
ActionListener Method
public void actionPerformed(ActionEvent e)
Contains the handler for the ActionEvent e that occurred.
Table 25: The ActionListener method
MouseListener Methods
public void mouseClicked(MouseEvent e)
Contains the handler for the event when the mouse is clicked (i.e., pressed and
released).
public void mouseEntered(MouseEvent e)
Contains the code for handling the case wherein the mouse enters a component.
public void mouseExited(MouseEvent e)
Contains the code for handling the case wherein the mouse exits a component.
public void mousePressed(MouseEvent e)
Invoked when the mouse button is pressed on a component.
public void mouseReleased(MouseEvent e)
Invoked when the mouse button is released on a component.
Table 26: The MouseListener methods
MouseListener Methods
public void mouseDragged(MouseEvent e)
Contains the code for handling the case wherein the mouse button is pressed on a
component and dragged. Called several times as the mouse is dragged.
public void mouseMoved(MouseEvent e)
Contains the code for handling the case wherein the mouse cursor is moved onto a
component, without the mouse button being pressed. Called multiple times as the
mouse is moved.
Table 27: The MouseMotionListener methods
WindowListener Methods
public void windowOpened(WindowEvent e)
Contains the code for handling the case when the Window object is opened (i.e., made
visible for the first time).
public void windowClosing(WindowEvent e)
Contains the code for handling the case when the user attempts to close Window object
from the object's system menu.
public void windowClosed(WindowEvent e)
Contains the code for handling the case when the Window object was closed after
calling dispose (i.e., release of resources used by the source) on the object.
public void windowActivated(WindowEvent e)
Invoked when a Window object is the active window (i.e., the window in use).
public void windowDeactivated(WindowEvent e)
Invoked when a Window object is no longer the active window.
public void windowIconified(WindowEvent e)
Called when a Window object is minimized.
public void windowDeiconified(WindowEvent e)
Called when a Window object reverts from a minimized to a normal state.
Table 28: The WindowListener methods
1. Create a class that describes and displays the appearance of your GUI application.
2. Create a class that implements the appropriate listener interface. This class may refer
to the same class as in the first step.
3. In the implementing class, override ALL methods of the appropriate listener interface.
Describe in each method how you would like the event to be handled. You may give
empty implementations for methods you don't want to handle.
4. Register the listener object, the instantiation of the listener class in step 2, with the
source component using the add<Type>Listener method.
import java.awt.*;
import java.awt.event.*;
}
public static void main(String args[]) {
MouseEventsDemo med = new MouseEventsDemo("Mouse Events
Demo");
med.launchFrame();
}
}
import java.awt.*;
import java.awt.event.*;
class CloseFrame extends Frame implements WindowListener {
Label label;
CloseFrame(String title) {
super(title);
label = new Label("Close the frame.");
this.addWindowListener(this);
}
void launchFrame() {
setSize(300,300);
setVisible(true);
}
public void windowActivated(WindowEvent e) {
}
public void windowClosed(WindowEvent e) {
}
public void windowClosing(WindowEvent e) {
setVisible(false);
System.exit(0);
}
public void windowDeactivated(WindowEvent e) {
}
public void windowDeiconified(WindowEvent e) {
}
public void windowIconified(WindowEvent e) {
}
public void windowOpened(WindowEvent e) {
}
public static void main(String args[]) {
CloseFrame cf = new CloseFrame("Close Window Example");
cf.launchFrame();
}
}
Running this program simply displays a frame like the following screen shot:
import java.awt.*;
import java.awt.event.*;
CloseFrame(String title) {
super(title);
label = new Label("Close the frame.");
this.addWindowListener(w);
}
void launchFrame() {
setSize(300,300);
setVisible(true);
}
import java.awt.*;
import java.awt.event.*;
CloseFrame(String title) {
super(title);
label = new Label("Close the frame.");
this.addWindowListener(new CFListener());
}
void launchFrame() {
setSize(300,300);
setVisible(true);
}
import java.awt.*;
import java.awt.event.*;
CloseFrame(String title) {
super(title);
label = new Label("Close the frame.");
this.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e){
dispose();
System.exit(1);
}
});
}
void launchFrame() {
setSize(300,300);
setVisible(true);
}
9 Threads
9.1 Objectives
You've been accustomed to programs that execute sequentially. A sequential program
refers to a program that has one flow of execution. It has a a starting point of execution,
an execution sequence, and an end. During runtime, there is exactly a single process
being executed.
However, in real world situations, there is a need to handle concurrent processes. These
are processes running at the same time. This is where threads come in.
1. Running
The thread is currently being executed and is in control of the CPU.
2. Ready to run
The thread can now be executed but is not yet given the chance to do so.
3. Resumed
After being previously blocked/suspended, the state is now ready to run.
4. Suspended
A thread voluntarily gives up control over the CPU to allow other threads to run.
5. Blocked
A blocked thread is one that is not able to run because it is waiting for a resource to
be available or an event to happen.
9.2.3 Priorities
To determine which thread receives CPU control and gets to be executed first, each
thread is assigned a priority. A priority is an integer value ranging from 1 to 10. The
higher the thread priority, the larger chance that the thread gets to be executed first.
For instance, assume that there are two threads and both are ready to run. The first
thread is assigned a priority of 5 while the second thread has a priority of 10. Say that
the first thread is already running when the second thread comes in. Then, the second
thread would receive control of the CPU and gets to be executed since it has a higher
priority compared to the currently running thread. This scenario is an example of a
context switch.
A context switch occurs when a thread snatches the control of CPU from another thread.
There are several ways on how a context switch may occur. One scenario is when a
running thread voluntarily relinquishes CPU control to give other threads opportunities to
run. In this case, the highest priority thread that is ready to run receives CPU control.
Another way for context switch to occur is when a running thread is preempted by a
higher priority thread as seen in the example that was just given.
It may also be possible that when the CPU becomes available, there is more than one
highest priority thread that is ready to run. For deciding which of two threads with the
same priority receives CPU control depends on the operating system. Windows 95/98/NT
uses time-sliced round-robin to handle this case. Each thread of same priority is given a
limited amount of time to execute before passing the CPU control to other threads of
equal priority. On the other hand, Solaris allows a thread to execute until it completes its
work or until it voluntarily relinquishes CPU control.
Thread Constructors
Thread()
Creates a new Thread object.
Thread(String name)
Creates a new Thread object with the specified name.
Thread(Runnable target)
Creates a new Thread object based on a Runnable object. target refers to the object
whose run method is called.
Thread(Runnable target, String name)
Creates a new Thread object with the specified name and based on a Runnable object.
Table 29: Thread constructors
9.3.2 Constants
The Thread class also provides constants for priority values. The following table gives a
field summary of the Thread class.
Thread Constants
public final static int MAX_PRIORITY
The maximum priority value, 10.
public final static int MIN_PRIORITY
The minimum priority value, 1.
public final static int NORM_PRIORITY
The default priority value, 5.
Table 30: Thread constants
9.3.3 Methods
Now, these are some of the methods provided in the Thread class.
Thread Methods
public static Thread currentThread()
Returns a reference to the thread that is currently running.
public final String getName()
Returns the name of this thread.
public final void setName(String name)
Thread Methods
Renames the thread to the specified argument name. May throw SecurityException.
public final int getPriority()
Returns the priority assigned to this thread.
public final boolean isAlive()
Indicates whether this thread is running or not.
public final void join([long millis, [int nanos]])
An overloaded method. The currently running thread would have to wait until this
thread dies (if no parameter is specified), or until the specified time is up.
public static void sleep(long millis)
Suspends the thread for millis amount of time. May throw InterruptedException.
public void run()
Thread execution begins with this method.
public void start()
Causes thread execution to begin by calling the run method.
Table 31: Thread methods
import javax.swing.*;
import java.awt.*;
cdg.startCount();
}
}
The CountDownGui program simply counts down from 10 to 1 and then prints
information about the currently running thread. Here are some screen shots from
running the code.
class TestThread {
public static void main(String args[]) {
PrintNameThread pnt1 = new PrintNameThread("A");
PrintNameThread pnt2 = new PrintNameThread("B");
PrintNameThread pnt3 = new PrintNameThread("C");
PrintNameThread pnt4 = new PrintNameThread("D");
}
}
Observe that the reference variables pnt1, pnt2, pnt3, and pnt4 are simply used once.
For this application, there is really no need to use variables to refer to each thread. You
can replace the body of the main method with the following statements:
new PrintNameThread("A");
new PrintNameThread("B");
new PrintNameThread("C");
new PrintNameThread("D");
The program produces different outputs for each run. Here is a sample output.
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCDABCDABCDABCDABCDABCDA
BCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD
ABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABC
DABCDABCDABCDABCDABCDABCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBC
DBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBCDBC
DBCDBCDBCDBCDBCDBCDBCDBCD
The following example is similar to the last example you studies but uses the second way
of creating threads instead.
}
public void run() {
String name = thread.getName();
for (int i = 0; i < 100; i++) {
System.out.print(name);
}
}
}
class TestThread {
public static void main(String args[]) {
new PrintNameThread("A");
new PrintNameThread("B");
new PrintNameThread("C");
new PrintNameThread("D");
}
}
class TestThread {
public static void main(String args[]) {
PrintNameThread pnt1 = new PrintNameThread("A");
PrintNameThread pnt2 = new PrintNameThread("B");
PrintNameThread pnt3 = new PrintNameThread("C");
PrintNameThread pnt4 = new PrintNameThread("D");
System.out.println("Running threads...");
try {
pnt1.thread.join();
pnt2.thread.join();
pnt3.thread.join();
pnt4.thread.join();
} catch (InterruptedException ie) {
}
System.out.println("\nThreads killed."); //printed last!
}
}
Try running this program yourself. What have you noticed? Through the join method
calls, we are assured that the last statement is executed at the last part.
Running threads...
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCDBCD
BCDBCDBCBCBCBCBCBCDBDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDCCCC
CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
CCCCCCCCCCCCCCCCCCCCCC
Threads killed.
Now, comment out the try-catch block where the join method was invoked. Is there any
difference in the program output?
9.5 Synchronization
So far, you've seen examples of threads that are running concurrently but are
independent of each other. That is, threads run at their own pace without concern for the
status and activities of the other concurrently running threads. In this instances, each
thread do not require any outside resources or methods and as a result, does not need to
communicate with other threads.
class TwoStrings {
static void print(String str1, String str2) {
System.out.print(str1);
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
System.out.println(str2);
}
}
The program is expected to print out the two arguments of the Runnable objects
consecutively. The problem, however, is the invocation of the sleep method causes other
threads to be executed when some other thread is not yet finished with the execution of
the print method of the TwoStrings class. Here is a sample output.
Hello How are Thank you there.
you?
very much!
In this run, the three threads got to have their first string argument printed before
having their second argument printed. This results in a cryptic output.
Actually, the example here doesn't pose a very serious problem but for other
applications, this may cause some exceptions or problems to occur.
For synchronizing a method, the synchronized keyword can be prefixed to the header of
the method definition. In the case that you cannot modify the source code of the
method, you can synchronize the object of which the method is a member of. The syntax
for synchronizing an object is as follows:
synchronized (<object>) {
//statements to be synchronized
}
With this, the object's methods can only be invoked by one thread at a time.
class TwoStrings {
synchronized static void print(String str1, String str2) {
System.out.print(str1);
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
System.out.println(str2);
}
}
}
}
class TestThread {
public static void main(String args[]) {
new PrintStringsThread("Hello ", "there.");
new PrintStringsThread("How are ", "you?");
new PrintStringsThread("Thank you ", "very much!");
}
}
Hello there.
How are you?
Thank you very much!
class TwoStrings {
static void print(String str1, String str2) {
System.out.print(str1);
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
}
System.out.println(str2);
}
}
class TestThread {
public static void main(String args[]) {
TwoStrings ts = new TwoStrings();
new PrintStringsThread("Hello ", "there.", ts);
new PrintStringsThread("How are ", "you?", ts);
new PrintStringsThread("Thank you ", "very much!", ts);
}
}
Observe that in this scenario, a party that waits only wakes up once the other party
notifies him. The same is true for threads.
class SharedData {
int data;
synchronized void set(int value) {
System.out.println("Generate " + value);
data = value;
}
synchronized int get() {
System.out.println("Get " + data);
return data;
}
}
sd.set((int)(Math.random()*100));
}
}
}
class TestProducerConsumer {
public static void main(String args[]) throws Exception {
SharedData sd = new SharedData();
new Producer(sd);
new Consumer(sd);
}
}
Generate 8
Generate 45
Generate 52
Generate 65
Get 65
Generate 23
Get 23
Generate 49
Get 49
Generate 35
Get 35
Generate 39
Get 39
Generate 85
Get 85
Get 85
Get 85
Generate 35
Get 35
Get 35
This is not what we wanted the program to do. For every value produced by the
producer, we expect the consumer to get each value. Here is the output we expect
instead.
Generate 76
Get 76
Generate 25
Get 25
Generate 34
Get 34
Generate 84
Get 84
Generate 48
Get 48
Generate 29
Get 29
Generate 26
Get 26
Generate 86
Get 86
Generate 65
Get 65
Generate 38
Get 38
Generate 46
Get 46
To fix the problem with this code, we use the methods for interthread communication.
The following implementation of the Producer-Consumer problem uses the methods for
interthread communication.
class SharedData {
int data;
boolean valueSet = false;
synchronized void set(int value) {
if (valueSet) { //has just produced a value
try {
wait();
} catch (InterruptedException ie) {
}
}
System.out.println("Generate " + value);
data = value;
valueSet = true;
notify();
}
synchronized int get() {
if (!valueSet) { //producer hasn't set a value yet
try {
wait();
} catch (InterruptedException ie) {
}
}
System.out.println("Get " + data);
valueSet = false;
notify();
return data;
}
}
class TestProducerConsumer {
public static void main(String args[]) throws Exception {
SharedData sd = new SharedData();
new Producer(sd);
new Consumer(sd);
}
}
Without the use of this interface, we execute Runnable tasks by creating Thread
instances and calling the start method of the the Thread object. The following code
demonstrates a way of doing this:
new Thread(<aRunnableObject>).start();
With the availability of this new interface, submitted Runnable objects are executed
using its execute method as follows:
<anExecutorObject>.execute(<aRunnableObject>);
The new Executor framework is useful for multithreaded applications. Because threads
need stack and heap space, thread creation can be expensive. As a result, creation of
several threads may cause out of memory errors. A way to get around this problem is
with thread pooling. In thread pooling, a thread is queued to the pool after it completes
its assigned task rather than dying or terminating. However, implementing a well-
designed thread pooling scheme is not simple. Another problem was the difficulty in
cancellation and shutting down of threads.
The Executor framework solves these problems by decoupling task submission from the
mechanics of how each task will be run, including details of thread use, scheduling and
others. It is normally used instead of explicitly creating threads. Rather than creating a
thread and running it via the start method for each set of task, it is more advisable to
use the following code fragment instead:
Creates a thread pool that reuses a fixed set of threads operating off a shared
unbounded queue. An overloaded method, which takes in a ThreadFactory object as
an additional parameter.
public static ScheduledExecutorService newScheduledThreadPool(int
corePoolSize)
Creates a thread pool that can schedule commands to run after a given delay, or to
execute periodically. An overloaded method, which takes in a ThreadFactory object as
an additional parameter.
public static ExecutorService newSingleThreadExecutor()
Creates an Executor that uses a single worker thread operating off an unbounded
queue. An overloaded method, which also takes in a ThreadFactory object as an
argument.
public static ScheduledExecutorService newSingleThreadScheduledExecutor()
Creates a single-threaded executor that can schedule commands to run after a given
delay, or to execute periodically. An overloaded method, which also takes in a
ThreadFactory object as an argument.
Table 33: Factory Methods of the Executors Class
The Runnable tasks are executed and finished under the control of the Executor
interface. To stop the threads, we can simply invoke the shutdown method of the
interface as follows:
executor.shutdown();
The Callable interface is basically the same as the Runnable interface without its
drawbacks. To get the result from a Runnable task, we have to use some external means
of getting the result. A common technique of which is to use an instance variable for
storing the result. The next code shows how this can be done.
}
}
With the Callable interface, getting the result is simple as shown in the next example.
import java.util.concurrent.*;
V here is a generic type, which means that the return type of call can be of any reference
type. You will learn more about generic types in a latter chapter.
There are still more concurrency features in J2SE5.0. Please refer to the API
documentation for a detailed discussion of these other features.
10 Networking
Java allows you to easily develop applications that perform a variety of tasks over a
network. This is one of Java's strength since it was created with the Internet in mind.
Before learning about Java networking, you will first be introduced to some basic
concepts on networking.
10.1.1 IP Address
Each of the computers connected to the Internet have a unique IP address. The IP
address is logically similar to the traditional mailing address in the sense that an address
uniquely identifies a particular object. It is a 32-bit number used to uniquely identify
each computer connected to the Internet. 192.1.1.1 is an example of an IP address.
They may also come in symbolic forms such as docs.rinet.ru.
10.1.2 Protocol
Since there are many different types of communication that may occur over the Internet,
there must also be an equal number of mechanisms for handling them. Each type of
communication requires a specific and unique protocol.
A protocol refers to a set of rules and standards that define a certain type of Internet
communication. It describes the format of data being sent over the Internet, along with
how and when it is sent.
The concept of a protocol is actually not entirely new to us. Consider how many times
you have used this type of conversation:
"Hello."
"Hello. Good afternoon. May I please speak at Joan?"
"Okay, please wait for a while."
"Thanks."
...
This is a social protocol used when involved in a telephone conversation. This type of
protocols gives us confidence and familiarity of knowing what to do in certain situations.
Let's now take a look at some important protocols used over the Internet. Without a
doubt, Hypertext Transfer Protocol (HTTP) is one of the most commonly used protocol. It
is used to transfer HTML documents on the Web. Then, there's File Transfer Protocol,
which is more general compared to HTTP and allows you to transfer binary files over the
Internet. Both protocols have their own set of rules and standards on how data is
transferred. Java provides support for both protocols.
10.1.3 Ports
Now, protocols only make sense when used in the context of a service. For instance,
HTTP protocol is used when you are providing Web content through an HTTP service.
Each computer on the Internet can provide a variety of services through the various
protocols supported. The problem, however, is that the type of service must be known
before information can be transferred. This is where ports come in.
A port is a 16-bit number that identifies each service offered by a network server. To use
a particular service and hence, establish a line of communication through a specific
protocol, you need to connect to the appropriate port. Ports are associated with a
number and some of these numbers are specifically associated with a particular type of
service. Such ports with specific service assignments are called standard ports. For
example, the FTP service is located on port 21 while the HTTP service is located on port
80. If you want to perform an FTP file transfer, you need to connect to port 21 of the
host computer. Now, all standard service assignments are given port values below 1024.
Port values above 1024 are available for custom communication. In the case that a port
value above 1024 is already in use by some custom communication, you must look for
other unused values.
The paradigm describes a simple scenario. Typically, a client connects to a server and
queries for certain information. The server then considers the query and returns
information available on it to the client.
10.1.5 Sockets
The last general networking concept we'll be looking at before plunging into Java
networking is regarding sockets. Most Java network programming uses a particular type
of network communication known as sockets.
ServerSocket Constructors
ServerSocket(int port)
Instantiates a server that is bound to the specified port. A port of 0 assigns the server
to any free port. Maximum queue length for incoming connection is set to 50 by default.
ServerSocket(int port, int backlog)
Instantiates a server that is bound to the specified port. Maximum queue length for
incoming connection is is based on the backlog parameter.
Table 34: ServerSocket constructors
ServerSocket Methods
public Socket accept()
Causes the server to wait and listen for client connections, then accept them.
public void close()
Closes the server socket. Clients can no longer connect to the server unless it is opened
again.
public int getLocalPort()
Returns the port on which the socket is bound to.
public boolean isClosed()
Indicates whether the socket is closed or not.
Table 35: ServerSocket methods
import java.net.*;
import java.io.*;
try {
server = new ServerSocket(1234);
//1234 is an unused port number
} catch (IOException ie) {
System.out.println("Cannot open socket.");
System.exit(1);
}
while(true) {
try {
client = server.accept();
OutputStream clientOut = client.getOutputStream();
PrintWriter pw = new PrintWriter(clientOut, true);
InputStream clientIn = client.getInputStream();
BufferedReader br = new BufferedReader(new
InputStreamReader(clientIn));
pw.println(br.readLine());
} catch (IOException ie) {
}
}
}
}
While the ServerSocket class implements server sockets, the Socket class implements a
client socket. The Socket class has eight constructors, two of which are already
deprecated. Let us have a quick look at two of these constructors.
Socket Constructors
Socket(String host, int port)
Creates a client socket that connects to the given port number on the specified host.
Socket(InetAddress address, int port)
Creates a client socket that connects to the given port number at the specified IP
address.
Table 36: Socket constructors
Socket Methods
public void close()
Closes the client socket.
public InputStream getInputStream()
Retrieves the input stream associated with this socket.
public OutputStream getOutputStream()
Retrieves the output stream associated with this socket.
public InetAddress getInetAddress()
Returns the IP address to which this socket is connected
public int getPort()
Returns the remote port to which this socket is connected.
public boolean isClosed()
Indicates whether the socket is closed or not.
Table 37: Socket methods
import java.io.*;
import java.net.*;
Running the EchoingServer makes it ready for accepting message from the client. Once a
client, such as MyClient, sends a message to the server, the server echoes the message
back to the client. Here's a sample run of MyClient once EchoingServer has been started:
MulticastSocket Constructors
MulticastSocket(int port)
Creates a multicast socket bound to the given port number.
Table 38: MulticastSocket constructor
MulticastSocket Methods
public void joinGroup(InetAddress mcastaddr)
Join a multicast group on the specified address.
public void leaveGroup(InetAddress mcastaddr)
Leave a multicast group on the specified address.
public void send(DatagramPacket p)
An inherited method from the DatagramSocket class. Sends p from this socket.
Table 39: MulticastSocket methods
Before one can send a message to a group, one should first be a member of the
multicast group by using the joinGroup method. A member can now send messages
through the send method. Once you're done talking with the group, you can use the
leaveGroup method to relinquish your membership.
Before looking at an example of using the MulticastSocket class, let's first have a quick
look at the DatagramPacket class. Observe that in the send method of the
The DatagramPacket class is used to deliver data through a connectionless protocol such
as a multicast. A problem with this is that the delivery of packets is not guaranteed. Let
us now consider two of its six constructors.
DatagramPacket Constructors
DatagramPacket(byte[] buf, int length)
Constructs a datagram packet for receiving packets with a length length. length should
be less than or equal to the size of the buffer buf.
DatagramPacket(byte[] buf, int length, InetAddress address, int port)
Constructs a datagram packet for sending packets with a length length to the specified
port number on the specified host.
Table 40: DatagramPacket constructors
DatagramPacket Methods
public byte[] getData()
Returns the buffer in which data has been stored.
public InetAddress getAddress()
Returns the IP address of the machine where the packet is being sent to or was
received from.
public int getLength()
Returns the length of data being sent or received.
public int getPort()
Returns the port number on the remote host where the packet is being sent to or was
received from.
Table 41: DatagramPacket methods
Our multicast example also consists of two classes, a server and a client. The server
receives messages from the client and prints out these messages.
Here is the server class.
import java.net.*;
import java.net.*;
import java.io.*;
Here is a sample run of ChatServer and ChatClient class, assuming that ChatServer was
executed before running the client class:
11 Applets
11.1 Objectives
Applets are one of the most interesting features in Java. This refers to programs you run
over via a web browser. You will learn about creating applets in this lesson.
In this module, you will learn about creating applets using the AWT.
import java.awt.*;
import java.applet.*;
/* insert this part in the html code
<applet code="AppletDemo" width=300 height=100>
</applet>
*/
After compilation, try running this example using the java command. What happens?
Remember that applets are special Java applications. They are not executed using the
java command. Instead, the applet is run on a web browser or using the applet viewer.
To open the applet through a web browser, simply open the HTML document in which the
applet is embedded using the applet HTML tag (the commented out code in the Hello
World example).
Another way of running an applet is through the appletviewer command. Simply follow
this syntax:
appletviewer AppletDemo.java
The HTML tag in the given example indicates that an applet be created with a width of
300 pixels and a height of 100 pixels. Then, the drawString method draws the "Hello
world!" string at the pixel position (80,25) counting down then right.
browser or the applet viewer interacts with the applet through the following methods:
1. init()
init is the first method called. It is invoked exactly once when the applet is loaded.
2. start()
After the invoking the init method, start is the next method called. It is invoked
everytime the applet's HTML document is displayed. Execution resumes with this
method when the applet is redisplayed.
3. stop()
When the web browser leaves the applet's HTML document, this method is called to
inform the applet that it should stop its execution.
4. destroy()
This method is called when the applet needs to be removed from the memory
completely. The stop method is always called before this method is invoked.
When creating applets, at least some of these methods are overriden. The following
applet example overrides these methods.
import java.applet.*;
import java.awt.*;
/*
<applet code="LifeCycleDemo" width=300 height=100>
</applet>
*/
<HTML>
<TITLE>Life Cycle Demo</TITLE>
<applet code="LifeCycleDemo" width=300 height=100>
</applet>
</HTML>
import java.awt.*;
import java.applet.*;
/*
<applet code="AppletDemo" width=300 height=100>
</applet>
*/
The next example continually plays an audio file until the applet's stop method is called.
import java.awt.*;
import java.applet.*;
/*
<applet code="AudioApplet" width=300 height=100>
</applet>
*/
<APPLET
[CODEBASE = codebaseURL]
CODE = appletFile
[ATL = alternateText]
[NAME = appletInstanceName]
WIDTH = widthInPixels HEIGHT = heightInPixels
[ALIGN = alignment]
[VSPACE = vspaceInPixels] [HSPACE = hspaceInPixels]
>
[<PARAM NAME = parameterName1 VALUE = parameterValue1>]
[<PARAM NAME = parameterName2 VALUE = parameterValue2>]
...
[<PARAM NAME = parameterNamen VALUE = parameterValuen>]
[HTML that will be dsiplayed in the absence of Java]
</APPLET>
The example below demonstrates how to access parameter specified at the HTML tag.
import java.awt.*;
import java.applet.*;
/*
<applet code="ParamDemo" width=300 height=100>
<param name="myParam" value="Hello world!">
</applet>
*/
The output of this program is just the same as that of Hello World applet. Here's a screen
shot of the expected output.
12.1 Objectives
In a previous module, you've learned how to get user input and manipulate files using
streams. You will now learn more about streams and other stream classes.
The InputStream class is the abstract root class of all input byte streams whereas the
OutputStream class is the abstract root class of all output byte streams. For character
streams, the corresponding superclass of all classes are the Reader and the Writer class,
respectively. Both classes are abstract classes for reading and writing to character
streams.
The InputStream class and the Reader class are the superclasses of all input streams.
The OutputStream class and the Writer class are the root classes of all output streams.
Input streams are also known as source streams since we get information from these
The succeeding sections gives an overview of the different stream classes. For a
complete list of these classes, please refer to Java's API documentation.
A File Constructor
File(String pathname)
Instantiates a File object with the specified pathname as its filename. The filename may
either be absolute (i.e., containes the complete path) or may consists of the filename
itself and is assumed to be contained in the current directory.
Table 43: File constructor
The File class provides several methods for manipulating files and directories. Here are
some of these methods.
File Methods
public String getName()
Returns the filename or the directory name of this File object.
public boolean exists()
Tests if a file or a directory exists.
public long length()
Returns the size of the file.
public long lastModified()
Returns the date in milliseconds when the file was last modified.
public boolean canRead()
Returns true if it's permissible to read from the file. Otherwise, it returns false.
public boolean canWrite()
Returns true if it's permissible to write to the file. Otherwise, it returns false.
public boolean isFile()
Tests if this object is a file, that is, our normal perception of what a file is (not a
directory).
public boolean isDirectory()
Tests if this object is a directory.
public String[] list()
Returns the list of files and subdirectories within this object. This object should be a
directory.
public void mkdir()
Creates a directory denoted by this abstract pathname.
public void delete()
File Methods
Removes the actual file or directory represented by this File object.
Table 44: File methods
Let's see how these methods work by trying out the following example:
import java.io.*;
Name: temp.txt
temp.txt is a file.
temp.txt is 34 bytes long.
temp.txt was last modified on 1149150489177.
temp.txt has contains the following text:
Reader Methods
public int read(-) throws IOException
An overloaded method, which has three versions. Reads character(s), an entire
character array or a portion of a character array.
public int read() - Reads a single character.
public int read(char[] cbuf)- Reads characters and stores them in character array
cbuf.
public abstract int read(char[] cbuf, int offset, int length)- Reads up to
length number of characters and stores them in character array cbuf starting at the
specified offset.
public abstract void close() throws IOException
Closes this stream. Calling the other Reader methods after closing the stream would
cause an IOException to occur.
public void mark(int readAheadLimit) throws IOException
Marks the current position in the stream. After marking, calls to reset() will attempt to
reposition the stream to this point. Not all character-input streams support this
operation.
public boolean markSupported()
Indicates whether a stream supports the mark operation or not. Not supported by
default. Should be overidden by subclasses.
public void reset() throws IOException
Repositions the stream to the last marked position.
Table 45: Reader methods
Writer Methods
public void write(-) throws IOException
An overloaded method with five versions:
public void write(int c) – Writes a single character represented by the given
integer value.
public void write(char[] cbuf) – Writes the contents of the character array cbuf.
public abstract void write(char[] cbuf, int offset, int length) – Writes
length number of characters from the cbuf array, starting at the specified offset.
public void write(String str) – Writes the string string.
public void write(String str, int offset, int length) – Writes length number
of characters from the string str, starting at the specified offset.
public abstract void close() throws IOException
Closes this stream after flushing any unwritten characters. Invocation of other methods
after closing this stream would cause an IOException to occur.
public abstract void flush()
Flushes the stream (i.e., characters saved in the buffer are immediately written to the
intended destination).
Table 48: Writer methods
import java.io.*;
class CopyFile {
void copy(String input, String output) {
FileReader reader;
FileWriter writer;
int data;
try {
reader = new FileReader(input);
writer = new FileWriter(output);
while ((data = reader.read()) != -1) {
writer.write(data);
}
reader.close();
writer.close();
} catch (IOException ie) {
ie.printStackTrace();
}
}
Try out the program yourself and observe what happens to the files manipulated.
Using temp.txt from our previous example, here's the result when we pass temp.txt as
the inputFile and temp2.txt as the outputFile:
import java.io.*;
class CopyFile {
void copy(String input, String output) {
BufferedReader reader;
BufferedWriter writer;
String data;
try {
reader = new BufferedReader(new FileReader(input));
writer = new BufferedWriter(new FileWriter(output));
while ((data = reader.readLine()) != null) {
writer.write(data, 0, data.length());
}
reader.close();
writer.close();
} catch (IOException ie) {
ie.printStackTrace();
}
}
Compare this code with the previous one. What is the result of running this program?
InputStream Methods
public int read(-) throws IOException
An overloaded method, which also has three versions like that of the Reader class.
Reads bytes.
public abstract int read() - Reads the next byte of data from this stream.
public int read(byte[] bBuf)- Reads some number of bytes and stores them in the
bBuf byte array.
public abstract int read(char[] cbuf, int offset, int length)- Reads up to
length number of bytes and stores them in the byte array bBuf starting at the specified
offset.
public abstract void close() throws IOException
Closes this stream. Calling the other InputStream methods after closing the stream
would cause an IOException to occur.
public void mark(int readAheadLimit) throws IOException
Marks the current position in the stream. After marking, calls to reset() will attempt to
reposition the stream to this point. Not all byte-input streams support this operation.
public boolean markSupported()
Indicates whether a stream supports the mark and reset operation. Not supported by
default. Should be overidden by subclasses.
public void reset() throws IOException
Repositions the stream to the last marked position.
Table 51: InputStream methods
OutputStream Methods
public void write(-) throws IOException
An overloaded method for writing bytes to the stream. It has three versions:
public abstract void write(int b) – Writes the specified byte value b to this
output stream.
public void write(byte[] bBuf) – Writes the contents of the byte array bBuf to this
stream.
public void write(byte[] bBuf, int offset, int length) – Writes length
number of bytes from the bBuf array to this stream, starting at the specified offset to
this stream.
public abstract void close() throws IOException
Closes this stream and releases any system resources associated with this stream.
Invocation of other methods after calling this method would cause an IOException to
occur.
public abstract void flush()
Flushes the stream (i.e., bytes saved in the buffer are immediately written to the
intended destination).
Table 54: OutputStream methods
import java.io.*;
class CopyFile {
void copy(String input, String output) {
FileInputStream inputStr;
FileOutputStream outputStr;
int data;
try {
inputStr = new FileInputStream(input);
outputStr = new FileOutputStream(output);
while ((data = inputStr.read()) != -1) {
outputStr.write(data);
}
inputStr.close();
outputStr.close();
} catch (IOException ie) {
ie.printStackTrace();
}
}
Passing tempo.txt and tempo2.txt as arguments, here's a sample run of this code:
import java.io.*;
class CopyFile {
void copy(String input) {
PushbackInputStream inputStr;
PrintStream outputStr;
int data;
try {
inputStr = new PushbackInputStream(new
FileInputStream(input));
outputStr = new PrintStream(System.out);
while ((data = inputStr.read()) != -1) {
outputStr.println("read data: " + (char) data);
inputStr.unread(data);
data = inputStr.read();
outputStr.println("unread data: " + (char) data);
}
inputStr.close();
outputStr.close();
} catch (IOException ie) {
ie.printStackTrace();
}
}
Test this code on a file containing a few lines or characters. Say, we have a file named
tempo.txt containing the following text:
one 1
two
read data: o
unread data: o
read data: n
unread data: n
read data: e
unread data: e
read data:
unread data:
read data: 1
unread data: 1
read data:
unread data:
read data:
unread data:
read data: t
unread data: t
read data: w
unread data: w
read data: o
unread data: o
12.12 Serialization
The Java Virtual Machine (JVM) supports the ability to read or write an object to a
stream. This capability is called serialization, the process of "flattening" an object so that
it can be saved to some permanent storage or passed to another object via the
OutputStream class. When writing an object, it is important that its state be written in a
serialized form such that the object can be reconstructed as it is being read. Saving an
object to some type of permanent storage is known as persistence.
The streams used for deserializing and serializing are the ObjectInputStream and the
ObjectOutputStream classes, respectively.
To allow an object to be serializable (i.e., can be saved and retrieved), its class should
implement the Serializable interface. The class should also provide a default constructor
or a constructor with no arguments. One nice thing about serializability is that it is
inherited, which means that we don't have to implement Serializable on every class. This
means less work for programmers. You can just implement Serializable once along the
class heirarchy.
Do not despair though. A class containing a non-serializable object can still be serialized
if the reference to this non-serializable object is marked with the transient keyword.
Consider the following example:
The transient keyword prevents the data from being serialized. Instantiating objects from
this class can now be written to an OutputStream.
The example below writes a Boolean object to an ObjectOutputStream. The Boolean class
implements the Serializable interface. Thus, objects instantiated from this class can be
written to and read from a stream.
import java.io.*;
try {
FileOutputStream fos = new
FileOutputStream("boolean.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(booleanData);
oos.close();
} catch (IOException ie) {
ie.printStackTrace();
}
}
import java.io.*;
try {
FileInputStream fis = new
FileInputStream("boolean.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
booleanData = (Boolean) ois.readObject();
ois.close();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Unserialized Boolean from " +
"boolean.ser");
System.out.println("Boolean data: " + booleanData);
System.out.println("Compare data with true: " +
booleanData.equals(new Boolean("true")));
}
13 An Introduction to Generics
13.1 Objectives
Java's latest release provides the biggest leap forward in Java programming compared to
its other versions. It includes significant extensions to the source language syntax. The
most visible of which is the addition of generic types.
This module introduces you to the basic concepts related to Java generic types.
The main goal of adding generics to Java is to solve this problem. Generic types allow a
single class to work with a wide variety of types. It is a natural way of eliminating the
need for casting.
Let's first consider an ArrayList object and see how generic types would help in
improving our code. As you already know, an ArrayList object has the ability to store
elements of any reference type to this list. An ArrayList instance, however, has always
forced us to downcast the objects we retrieve out of the list. Consider the following
statement:
The generic version of the ArrayList class is designed to work natively with any type of
class. At the same, it also preserves the benefits of type checking. We can do away with
the need of having to typecast the element we get from the list and have the following
statement instead of the previous one:
Although downcasting was already removed, this doesn't mean that you could assign
anything to the return value of the get method and do away with typecasting altogether.
If you assign anything else besides a String to the output of the get method, you would
found: java.lang.String
required: java.lang.Integer
Integer data = myArrayList.get(0);
For you to just have an idea how generic types are used before digging into more details,
consider the following code fragment:
Browsing through the statements, you probably observed the word <String> appearing
immediately after the reference data type ArrayList. You can interpret the first statement
as instantiating a generic version of the ArrayList class and this generic version contains
objects of type String. genArrList is bound to String type. Hence, binding an Integer or
some other non-String type to the result of the get function would be illegal. The next
statement is illegal.
Instead of having a lengthy discussion on how to declare a generic class, you are given a
simple generic class example to learn from.
}
public static void main(String args[]) {
GenSample sample = new GenSample();
System.out.println(sample.method("Some generic data"));
System.out.println(sample.method(1234));
}
}
Now let's go through the parts of the code that use the syntax for generic types.
For the declaration of the BasicGeneric class,
the class name is followed by a pair of brackets enclosing the capital letter A: <A>. This
is called a type parameter. Use of these brackets indicates that the class declared is a
generic class. This means that the class does not work with any specific reference type.
Then, observe that a field of the class was declared to be of type A.
private A data;
This declaration specifies that the field data is of generic type, depending on the data
type that the BasicGeneric object was designed to work with.
When declaring an instance of the class, you must specify the reference type with which
you want to work with.
The <String> syntax after the declaration BasicGeneric specifies that this instance of the
class is going to work with variables of type String.
You can also work with variables of type Integer or any other reference type. To work
with an Integer, the code fragment had the following statement:
You can probably interpret the rest of the code on your own. Consider the declaration of
the getData method.
public A getData() {
return data;
}
The method getData returns a value of type A, a generic type. This doesn't mean that
the method will not have a runtime data type, or even at compile time. After you declare
an object of type BasicGeneric, A is bound to a specific data type. This instance will act
as if it were declared to have this specific data type and this type only from the very
beginning.
In the given code, two instances of the BasicGeneric class were created.
Notice that instantiation of a generic class is just similar to instantiating a normal class
except that the specific data type enclosed in <> succeed the constructor name. This
additional information indicates the type of data you'll be working with for this particular
instance of the BasicGeneric class. After instantiation, you can now access members of
the class via the instance. There is no longer any need to typecast the return value of the
getData method since it has already been decided that it will work with a specific
reference data type.
For example, the following statement would be illegal since int is a primitive data type.
You'll have to wrap primitive types first before using them as arguments to a generic
type.
Here's an example:
For example, we may want to define a generic ScrollPane class that is a template for an
ordinary Container decorated with scrolling functionality. The runtime type of an instance
of this class will often be a subclass of Container, but the static or general type is simply
Container.
To limit the type instantiations of a class, we use the extends keyword followed by the
class bounding the generic type as part of the type parameter.
The following example limits type instantiation of the ScrollPane class to subtypes of the
Container class.
class TestScrollPane {
public static void main(String args[]) {
ScrollPane <Panel> scrollPane1 = new
ScrollPane <Panel>();
// The next statement is illegal
ScrollPane <Button> scrollPane2 = new
ScrollPane <Button>();
}
}
Using constrained generics give us added static type checking. As a result, we are
guaranteed that every instantiation of the generic type adheres to the bounds we
assigned to it.
Since we are assured that every type instantiation is a subclass of the assigned bound,
we can safely call any methods found in the object's static type. If we hadn't place any
explicit bound on the parameter, the default bound is Object. This means that we can't
invoke methods on an instance of the bound that don't appear in the Object class.
Parameterizing methods are useful when we want to perform tasks where the type
dependencies between the arguments and return value are naturally generic, but the
generic nature doesn't rely on any class-level type information and will change from
method call to method call.
For example, suppose we want to add a make method to an ArrayList class. This static
method would take in a single argument, which would be the sole element of the
ArrayList object. To make our ArrayList generic so as to accomodate any type of element,
the single argument in the make method should have a generic type as an argument and
as a return type.
class Utilities {
/* T implicitly extends Object */
public static <T> ArrayList<T> make(T first) {
return new ArrayList<T>(first);
}
}
Utilities.make(Integer(0));
Collection Methods
public boolean add(E o)
Inserts specified element o to this collection. Returns true if o was successfully added
to the collection.
public void clear()
Removes all elements of this collection.
public boolean remove(Object o)
Removes a single instance of the Object o from this collection, if it is present. Returns
true if o was found and removed from the collection.
public boolean contains(Object o)
Returns true if this collection contains the Object o.
public boolean isEmpty()
Returns true if this collection does not contain any object or element.
public int size()
Returns the number of elements in this collection.
public Iterator<E> iterator()
Returns an iterator that allows us to go through the contents of this collection.
public boolean equals(Object o)
Returns true if the Object o is equal to this collection.
public int hashCode()
Returns the hash code value (i.e., the ID) for this collection. Same objects or
collections have the same hash code value or ID.
Table 57: Collection methods
Here is a sample code that uses the generic version of the LinkedList class.
import java.util.*;
class LinkedListDemo {
public static void main(String args[]) {
LinkedList <Integer> list = new LinkedList <Integer>();
list.add(new Integer(1));
list.add(new Integer(2));
list.add(new Integer(1));
System.out.println(list);
[1, 2, 1]
[1, 2, 1]
References
1. Lee Chuk Munn. Object Oriented Programming with Java. July 19, 1999.
2. Sun Java Programming Student Guide SL-275. Sun Microsystems. April 2000.
10.Diagnosing Java Code: Java Generics Without the Pain, Part 1 by Eric Allen. Available
at http://www-106.ibm.com/developerworks/java/library/j-djc02113.html
14.Sequential and Parallel Sorting Algorithms: Quick Sort by Hans Werner Lang.
Available at
http://www.iti.fh-flensburg.de/lang/algorithmen/sortieren/quick/quicken.htm
19.http://www.leepoint.net/notes-java/background/tools/NetBeans.html
http://java.sun.com/j2se/1.4.1/docs/api/index.html