Java Programming/Print version2

From Wikibooks, open books for an open world
Jump to: navigation, search

Aggregate

In the previous chapters, we have discovered the array. An array stores a group of primitive types. To group objects, or to reference a group of objects, we can use Java aggregate classes. There are two main interfaces, those are java.util.Collection and java.util.Map . Implementations for those interfaces are not interchangeable.

Collection

The implementations of java.util.Collection interface are used for grouping simple java objects.

Example
We can group together all patients in a Hospital to a "patient" collection.

Map

The implementations of java.util.Map interface are used to represent mapping between "key" and "value" objects. A Map represents a group of "key" objects, where each "key" object is mapped to a "value" object.

Example
For each patient, there is one and only one main nurse assigned to. That association can be represented by a "patient-nurse" Map.

Choice

A collection is better when you have to access all the items at once. A map is better when you have to randomly access an item regularly.

Before selecting a particular collection implementation, ask the following question:

Can my collection contain the same elements, i.e. are duplicates allowed?

Can my collection contain the null element?

Should the collection maintain the order of the elements? Is the order important in any way?

How do you want to access an element? By index, key or just with an iterator?

Does the collection need to be synchronized?

From a performance perspective, which one needs to be faster, updates or reads?

From a usage perspective, which operation will be more frequent, updates or reads?

Once you know your needs, you can select an existing implementation. But first decide if you need a Collection, or a Map.

Note that the above associations are explicit. The objects them-self do not have any knowledge/information about that they are part in an association. But creating explicit associations between simple java objects is the main idea about using the aggregate/collection classes.


Collection

The most basic collection interface is called Collection. This interface gives the user the generic usage of a collection. All collections need to have the same basic operations. Those are:

  • Adding element(s) to the collection
  • Removing element(s) from the collection
  • Obtaining the number of elements in the collection
  • Listing the contents of the collection, (Iterating through the collection)
Computer code Code listing 5.1: CollectionProgram.java
 1 import java.util.Collection;   // Interface
 2 import java.util.ArrayList;    // Implementation
 3 
 4 public class CollectionProgram {
 5 
 6   public static void main(String[] args) {
 7     Collection myCollection = new ArrayList();
 8     myCollection.add("1");
 9     myCollection.add("2");
10     myCollection.add("3");
11     System.out.println("The collection contains " + myCollection.size() + " item(s).");
12 
13     myCollection.clear();
14     if (myCollection.isEmpty()) {
15       System.out.println("The collection is empty.");
16     } else {
17       System.out.println("The collection is not empty.");
18     }
19   }
20 }
Computer code Console for Code listing 5.1
The collection contains 3 item(s).
The collection is empty.

When you put an object in a collection, this object is not actually in the collection. Only its object reference is added to the collection. This means that if an object is changed after it was put in an collection, the object in the collection also changes. The code listing 5.2 computes the seven next days from tomorrow and stores each date in a list to read it afterwards. See what happens:

Computer code Code listing 5.2: SevenNextDays.java
 1 import java.util.ArrayList;
 2 import java.util.Calendar;
 3 import java.util.Collection;
 4 import java.util.Date;
 5 import java.util.GregorianCalendar;
 6 
 7 public class SevenNextDays {
 8 
 9   public static void main(String[] args) {
10    
11     // The calendar is set at the current date: today
12     Calendar calendar = new GregorianCalendar();
13 
14     Collection collectionOfDays = new ArrayList();
15     Date currentDate = new Date();
16     for (int i = 0; i < 7; ++i) {
17       // The calendar is now set to the next day
18       calendar.add(Calendar.DATE, 1);
19       currentDate.setTime(calendar.getTimeInMillis());
20 
21       collectionOfDays.add(currentDate);
22     }
23 
24     for (Object oneDay : collectionOfDays) {
25       System.out.println("The next day is: " + oneDay);
26     }
27   }
28 }
Computer code Console for Code listing 5.2

 The next day is: Tue Dec 12 19:33:04 UTC 2017
 The next day is: Tue Dec 12 19:33:04 UTC 2017
 The next day is: Tue Dec 12 19:33:04 UTC 2017
 The next day is: Tue Dec 12 19:33:04 UTC 2017
 The next day is: Tue Dec 12 19:33:04 UTC 2017
 The next day is: Tue Dec 12 19:33:04 UTC 2017
 The next day is: Tue Dec 12 19:33:04 UTC 2017

All collection items were meant to be updated to a different date but they all have been updated to the last one. This means that each update has updated all the collection items. The currentDate has been used to fill all the collection items. The collection didn't keep trace of the added values (one of the seven dates) but the added object references (currentDate). So the collection contains the same object seven times! To avoid this issue, we should have coded it this way:

Computer code Code listing 5.3: ActualSevenNextDays.java
 1 import java.util.ArrayList;
 2 import java.util.Calendar;
 3 import java.util.Collection;
 4 import java.util.Date;
 5 import java.util.GregorianCalendar;
 6 
 7 public class ActualSevenNextDays {
 8 
 9   public static void main(String[] args) {
10    
11     // The calendar is set at the current date: today
12     Calendar calendar = new GregorianCalendar();
13 
14     Collection collectionOfDays = new ArrayList();
15     for (int i = 0; i < 7; ++i) {
16       Date currentDate = new Date();
17       // The calendar is now set to the next day
18       calendar.add(Calendar.DATE, 1);
19       currentDate.setTime(calendar.getTimeInMillis());
20 
21       collectionOfDays.add(currentDate);
22     }
23 
24     for (Object oneDay : collectionOfDays) {
25       System.out.println("The next day is: " + oneDay);
26     }
27   }
28 }
Computer code Console for Code listing 5.3

 The next day is: Wed Dec 6 19:33:04 UTC 2017
 The next day is: Thu Dec 7 19:33:04 UTC 2017
 The next day is: Fri Dec 8 19:33:04 UTC 2017
 The next day is: Sat Dec 9 19:33:04 UTC 2017
 The next day is: Sun Dec 10 19:33:04 UTC 2017
 The next day is: Mon Dec 11 19:33:04 UTC 2017
 The next day is: Tue Dec 12 19:33:04 UTC 2017

Now each time we add an item to the collection, it is a different instance. All the items evolve separately. To add an object in a collection and avoid this item being changed each time the source object is changed, you have to copy or clone the object before you add it to the collection.

Generics

Objects put into a collection are upcasted to the Object class. This means that you need to cast the object reference back when you get an element out of the collection. It also means that you need to know the type of the object when you take it out. If a collection contains different types of objects, we will have difficulty finding out the type of the objects obtained from a collection at run time. For example. let's use this collection with two objects in it:

Example Code section 5.1: Collection feeding.
1 Collection ageList = new ArrayList();
2 ageList.add(new Integer(46));
3 ageList.add("50");

Example Code section 5.2: Collection reading.
1 Integer sum = new Integer(0);
2 for (Object age : ageList) {
3     sum = sum.add((Integer) age);
4 }
5 
6 if (!ageList.isEmpty()) {
7     System.out.println("The average age is " + sum / ageList.size());
8 }
Computer code Console for Code section 5.2
ClassCastException.

This error could have been found earlier, at compile time, by using generic types. The Generics have been added since JDK version 1.5. It is an enhancement to the type system of the Java language. All collection implementations since 1.5 now have a parameterized type <E>. The E refers to an Element type. When a collection is created, the actual Element type will replace the E. In the collection, the objects are now upcasted to E class.

Example Code section 5.3: Collection with generics.
1 Collection<Integer> ageList = new ArrayList<Integer>();
2 ageList.add(new Integer(46));     // Integer can be added
3 ageList.add("50");                // Compilation error, ageList can have only Integers inside

ageList is a collection that can contain only Integer objects as elements. No casting is required when we take out an element.

Example Code section 5.4: Item reading.
1 Integer age = ageList.get(0);

Generics are not mandatory but are is often used with the collection classes.

Collection classes

There is no direct implementation for the java.util.Collection interface. The Collection interface has five sub interfaces.

Figure 1: The five sub interfaces of the java.util.Collection interface.
Java collection interfaces.svg


Set

A set collection contains unique elements, so duplicates are not allowed. It is similar to a mathematical Set. When adding a new item to a set, the set calls the method int hashCode() of the item and compares its result to the hash code of all the already inserted items. If the hash code is not found, the item is added. If the hash code is found, the set calls the boolean equals(Object obj); method for all the set items with the same hashcode as the new item. If all equal-calls return false, the new item is inserted in the set. If an equal-call returns true, the new item is not inserted in the set.

Figure 2: Set class diagram.
Java collection set implementations.jpg


java.util.HashSet<E> 
This is the basic implementation of the Set interface. Not synchronized. Allows the null elements
java.util.TreeSet<E>
Elements are sorted, not synchronized. null not allowed
java.util.CopyOnWriteArraySet<E> 
Thread safe, a fresh copy is created during modification operation. Add, update, delete are expensive.
java.util.EnumSet<E extends Enum<E>> 
All of the elements in an enum set must come from a single enum type that is specified, explicitly or implicitly, when the set is created. Enum sets are represented internally as bit vectors.
java.util.LinkedHashSet<E> 
Same as HashSet, plus defines the iteration ordering, which is the order in which elements were inserted into the set.

Detecting duplicate objects in Sets

Set cannot have duplicates in it. You may wonder how duplicates are detected when we are adding an object to the Set. We have to see if that object exists in the Set or not. It is not enough to check the object references, the objects' values have to be checked as well.

To do that, fortunately, each java object has the boolean equals(Object obj), method available inherited from Object. You need to override it. That method will be called by the Set implementation to compare the two objects to see if they are equal or not.

There is a problem, though. What if I put two different type of objects to the Set. I put an Apple and an Orange. They can not be compared. Calling the equals() method would cause a ClassCastException. There are two solutions to this:

  • Solution one : Override the int hashCode() method and return the same values for the same type of objects and return different values for different type of objects. The equals() method is used to compare objects only with the same value of hashCode. So before an object is added, the Set implementation needs to:
    • find all the objects in the Set that have the same hashCode as the candidate object hashCode
    • and for those, call the equals() methods passing in the candidate object
    • if any of them returns true, the object is not added to the Set.
  • Solution two : Create a super class for the Apple and Orange, let's call it Fruit class. Put Fruits in the Set. You need to do the following:
    • Do not override the equals() and hashCode() methods in the Apple and Orange classes
    • Create appleEquals() method in the Apple class, and create orangeEquals() method in the Orange class
    • Override the hashCode() method in the Fruit class and return the same value, so the equals() is called by the Set implementation
    • Override the equals() method in the Fruit class for something like this.
Example Code section 5.5: equals method implementation.
 1 public boolean equals(Object obj) {
 2     boolean ret = false;
 3     if (this instanceof Apple &&
 4           obj instanceof Apple) {
 5         ret = this.appleEquals(obj);
 6     } else if (this instanceof Orange &&
 7               obj  instanceof Orange) {
 8         ret = this.orangeEquals(obj);  
 9     } else {
10         // Can not compare Orange to Apple
11        ret = false;
12     }
13     return ret;
14 }

Note:

  • Only the objects that have the same hashCode will be compared.
  • You are responsible to override the equals() and hashCode() methods. The default implementations in Object won't work.
  • Only override the hashCode() method if you want to eliminate value duplicates.
  • Do not override the hashCode() method if you know that the values of your objects are different, or if you only want to prevent adding the exactly same object.
  • Beware that the hashCode() may be used in other collection implementations, like in a Hashtable to find an object fast. Overriding the default hashCode() method may affect performance there.
  • The default hashCodes are unique for each object created, so if you decide not to override the hashCode() method, there is no point overriding the equals() method, as it won't be called.

SortedSet

The SortedSet interface is the same as the Set interface plus the elements in the SortedSet are sorted. It extends the Set Interface. All elements in the SortedSet must implement the Comparable Interface, furthermore all elements must be mutually comparable.

Note that the ordering maintained by a sorted set must be consistent with equals if the sorted set is to correctly implement the Set interface. This is so because the Set interface is defined in terms of the equals operation, but a sorted set performs all element comparisons using its compare method, so two elements that are deemed equal by this method are, from the standpoint of the sorted set, equal.

The SortedSet interface has additional methods due to the sorted nature of the 'Set'. Those are:

E first(); returns the first element
E last(); returns the last element
SortedSet headSet(E toElement); returns from the first, to the exclusive toElement
SortedSet tailSet(E fromElement); returns from the inclusive fromElement to the end
SortedSet subSet(E fromElement, E toElement); returns elements range from fromElement, inclusive, to toElement, exclusive. (If fromElement and toElement are equal, the returned sorted set is empty.)

List

In a list collection, the elements are put in a certain order, and can be accessed by an index. Duplicates are allowed, the same element can be added twice to a list. It has the following implementations:

Figure 3: List class diagram.
Java collection list implementations.jpg


java.util.Vector<E> 
Synchronized, use in multiple thread access, otherwise use ArrayList.
java.util.Stack<E> 
It extends class Vector with five operations that allow a vector to be treated as a stack. It represents a last-in-first-out (LIFO) stack of objects.
java.util.ArrayList<E> 
The basic implementation of the List interface is the ArrayList. The ArrayList is not synchronized, not thread safe. Vector is synchronized, and thread safe. Vector is slower, because of the extra overhead to make it thread safe. When only one thread is accessing the list, use the ArrayList. Whenever you insert or remove an element from the list, there are extra overhead to reindex the list. When you have a large list, and you have lots of insert and remove, consider using the LinkedList.
java.util.LinkedList<E> 
Non-synchronized, update operation is faster than other lists, easy to use for stacks, queues, double-ended queues. The name LinkedList implies a special data structure where the elements/nodes are connected by pointers.
 Head               Node 1                   Node 2                     Node n
  ______
 | Size |          _________________        _______________            _____________
 |______|         |      | point   |       |      | point  |          |      |      |  
 | First|-------->| Data | to next |------>| Data | to next|-- ... -->| Data | null |
 | elem |         |______|_________|       |______|________|          |______|______|
 |______|                                                                 ^
 | Last |                                                                 |
 | elem |-----------------------------------------------------------------
 |______|

Each node is related to an item of the linked list. To remove an element from the linked list the pointers need to be rearranged. After removing Node 2:

 Head               Node 1                   Node 2                     Node n
  ______                                 _____________________
 | Size |          _________________    |   _______________   |       ______________
 |_- 1__|         |      | point   |    |  |      | point  |  |       |      |      |  
 | First|-------->| Data | to next |----   | Data | to next|   -...-->| Data | null |
 | elem |         |______|_________|       |______|________|          |______|______|
 |______|                                                                 ^
 | Last |                                                                 |
 | elem |-----------------------------------------------------------------
 |______|
javax.management.AtributeList<E> 
Represents a list of values for attributes of an MBean. The methods used for the insertion of Attribute objects in the AttributeList overrides the corresponding methods in the superclass ArrayList. This is needed in order to insure that the objects contained in the AttributeList are only Attribute objects.
javax.management.relation.RoleList<E> 
A RoleList represents a list of roles (Role objects). It is used as parameter when creating a relation, and when trying to set several roles in a relation (via 'setRoles()' method). It is returned as part of a RoleResult, to provide roles successfully retrieved.
javax.management.relation.RoleUnresolvedList<E> 
A RoleUnresolvedList represents a list of RoleUnresolved objects, representing roles not retrieved from a relation due to a problem encountered when trying to access (read or write to roles).

Queue

The Queue interface provides additional insertion, extraction, and inspection operations. There are FIFO (first in, first out) and LIFO (last in, first out) queues. This interface adds the following operations to the Collection interface:

E element() Retrieves, but does not remove, the head of this queue. This method differs from the peek method only in that it throws an exception if this queue is empty
boolean offer(E o) Inserts the specified element into this queue, if possible.
E peek() Retrieves, but does not remove, the head of this queue, returning null if this queue is empty
E poll() Retrieves and removes the head of this queue, or null if this queue is empty
E remove() Retrieves and removes the head of this queue. This method differs from the poll method in that it throws an exception if this queue is empty.
Figure 4: Queue class diagram.
Java collection queue implementations.jpg


java.util.BlockingQueue<E> 
waits for the queue to become non-empty when retrieving an element, and waits for space to become available in the queue when storing an element. Best used for producer-consumer queues.
java.util.PriorityQueue<E> 
orders elements according to an order/priority specified at construction time, null element is not allowed.
java.util.concurrent.ArrayBlockingQueue<E> 
orders elements FIFO; synchronized, thread safe.
java.util.concurrent.SynchronousQueue<E> 
each put must wait for a take, and vice versa, does not have any internal capacity, not even a capacity of one, an element is only present when you try to take it; you cannot add an element (using any method) unless another thread is trying to remove it.

Complete UML class diagram

Figure 5: UML class diagram of the Collection interfaces and their implementations.
Java collection implementation.jpg


Synchronization

Synchronization is important when you are running several threads. Beware, synchronization does not mean that your collection is thread-safe. A thread-safe collection is also called a concurrent collection. Most of the popular collection classes have implementations for both single thread and multiple thread environments. The non-synchronized implementations are always faster. You can use the non-synchronized implementations in multiple thread environments, when you make sure that only one thread updates the collection at any given time.

A new Java JDK package was introduced at Java 1.5, that is java.util.concurrent. This package supplies a few Collection implementations designed for use in multi-threaded environments.

The following table lists all the synchronized collection classes:

synchronized non-synchronized
List java.util.Vector java.util.ArrayList
java.util.Stack
java.util.LinkedList
java.util.concurrent.CopyOnWriteArrayList
Set java.util.TreeSet
java.util.HashSet
java.util.LinkHashSet
java.util.concurrent.CopyOnWriteArraySet

Custom collection

The Java JDK collection implementations are quite powerful and good, so it is unlikely that you will need to write your own. The usage of the different collections are the same but the implementations are different. If the existing collection implementations do not meet your needs, you can write your version of the implementation. Your version of the implementation just needs to implement the same java.util.Collection interface, then you can switch to using your implementation and the code that is using the collection does not need to be changed.

Use the Collection interface if you need to keep related (usually the same type of) objects together in a collection where you can:

  • Search for a particular element
  • List the elements
  • Maintain and/or change the order of the elements by using the collection basic operations (Add, Remove, Update,..)
  • Access the elements by an index number

The advantages of using the Collection interface are:

  • Gives a generic usage, as we talked about above, it is easy to switch implementation
  • It makes it easy to convert one type of collection to another.

The Collection interface defines the following basic operations:

boolean add(E o); Using Element type E
boolean addAll(Collection c);
boolean remove(Object o);
boolean removeAll(Collection c);
boolean retainAll(Collection c); Return true if the collection has changed due to the operation.

Note that in addAll() we can add any type of collection. This is the beauty of using the Collection interface. You can have a LinkedList and just call the addAll(list) method, passing in a list. You can pass in a Vector, an ArrayList, a HashSet, a TreeSet, a YourImpOfCollection, ... All those different types of collection will be magically converted to a LinkedList.

Let's have a closer look at this magic. The conversion is easy because the Collection interface defines a standard way of looping through the elements. The following code is a possible implementation of addAll() method of the LinkedList.

Example Code section 5.6: Collection transfer.
 1 import java.util.Collection
 2 import java.util.Iterator
 3 ...
 4 public boolean addAll(Collection coll) {
 5    int sizeBefore = this.size();
 6    Iterator iter = coll.iterator();
 7    while(iter.hasNext()) {
 8       this.add(iter.next());
 9    }
10    if (sizeBefore > this.size()) {
11       return true;
12    } else {
13       return false;
14    }
15 }

The above code just iterates through the passed in collection and adds the elements to the linked list. You do not have to do that, since that is already defined. What you might need to code for is to loop through a Customer collection:

Example Code section 5.7: Iteration on a collection.
 1 import java.util.Collection
 2 import java.util.Iterator
 3 import java.yourcompany.Customer
 4 ...
 5 public String printCustomerNames(Collection customerColl) {
 6    StringBuffer buf = new StringBuffer();
 7 
 8    Iterator iter = customerColl.iterator();
 9    while(iter.hasNext()) {
10       Customer cust = (Customer) iter.next();
11       buf.append(cust.getName());
12       buf.append( "\n" );
13    }
14   return buf.toString();
15 }

Notice two things:

  • The above code will work for all type of collections.
  • We have to know the type of objects inside the collection, because we call a method on it.



ArrayList

The ArrayList class extends AbstractList and implements the List interface. ArrayList supports dynamic arrays that can grow as needed.

Standard Java arrays are of a fixed length. After arrays are created, they cannot grow or shrink, which means that you must know in advance how many elements an array will hold.

Array lists are created with an initial size. When this size is exceeded, the collection is automatically enlarged. When objects are removed, the array may be shrunk.

Initializing

The ArrayList class supports three constructors. The first constructor builds an empty array list.:

ArrayList( )

The following constructor builds an array list that is initialized with the elements of the collection c.

ArrayList(Collection c)

The following constructor builds an array list that has the specified initial capacity. The capacity is the size of the underlying array that is used to store the elements.

The capacity grows automatically as elements are added to an array list.

 ArrayList(int capacity)

Methods

ArrayList defines following methods:

Adding Element in ArrayList

  • Inserts the specified element at the specified position index in this list. Throws IndexOutOfBoundsException if the specified index is out of range (index < 0 || index >= size()).
void add(int index, Object element)
  • Appends the specified element to the end of this list.
boolean add(Object o)
  • Appends all of the elements in the specified collection to the end of this list, in the order that they are returned by the specified collection's iterator. Throws NullPointerException if the specified collection is null.
boolean addAll(Collection c)
  • Inserts all of the elements in the specified collection into this list, starting at the specified position. Throws NullPointerException if the specified collection is null.
boolean addAll(int index, Collection c)

Size of ArrayList

  • Returns the number of elements in this list.
int size()

Adding Element and Size of ArrayList

 
import java.util.*;

public class ArrayListDemo{
	public static void main(String[] args) {
		// create an array list
		ArrayList al= new ArrayList();
		System.out.println("Initial ArrayList : "+al);
		
		 // add elements to the array list
		al.add("A");
		al.add("B");
		
		//find size of ArrayList
		System.out.println("Size of al :"+al.size());
		// display the array list
		System.out.println("Contents of al :"+al);
		al.add(1,"C");
		System.out.println("Contents of al :"+al);
		System.out.println("Size of al :"+al.size());
	}
}

Output for Adding Element and Size of ArrayList

Computer code
Initial ArrayList : []
Size of al :2
Contents of al :[A, B]
Contents of al :[A, C, B]
Size of al :3


Get and Set ArrayList Element

  • Returns the element at the specified position in this list. Throws IndexOutOfBoundsException if the specified index is is out of range (index < 0 or index >= size()).
Object get(int index)
  • Replaces the element at the specified position in this list with the specified element. Throws IndexOutOfBoundsException if the specified index is is out of range (index < 0 or index >= size()).
Object set(int index, Object element)

Find Index of ArrayList Element

  • Returns the index in this list of the first occurrence of the specified element, or -1 if the List does not contain this element.
int indexOf(Object o)
  • Returns the index in this list of the last occurrence of the specified element, or -1 if the list does not contain this element.
int lastIndexOf(Object o)

Find Element Contain in ArrayList

  • Returns true if this list contains the specified element. More formally, returns true if and only if this list contains at least one element e such that (o==null ? e==null : o.equals(e)).
boolean contains(Object o)

Different Method in ArrayList

 
public class ArrayListDemo {
	public static void main(String[] args) {
		// create an array list
		ArrayList al = new ArrayList();

		// add elements to the array list
		al.add("A");
		al.add("B");
		al.add("C");
		al.add("A");
		al.add("D");
		al.add("A");
		al.add("E");
		System.out.println("Contents of al : " + al);

		// find index of element in ArrayList
		System.out.println("Index of D : " + al.indexOf("D"));
		System.out.println("Index of A : " + al.indexOf("A"));

		// find index of element in ArrayList
		System.out.println("Index of A : " + al.lastIndexOf("A"));

		// get element at given Index
		System.out.println("Element at Second Index : " + al.get(2));
		System.out.println("Element at Sixth Index : " + al.get(6));
		
		//set element at given Index
		al.set(3,"B"); // replacing third index element by "B"
		System.out.println("Contents of al : " + al);
		
		//check ArrayList contains given element
		System.out.println("ArrayList contain D : "+al.contains("D"));
		System.out.println("ArrayList contain F : "+al.contains("F"));
	}
}

Output for Different Method in ArrayList

Computer code
Contents of al : [A, B, C, A, D, A, E]
Index of D : 4
Index of A : 0
Index of A : 5
Element at Second Index : C
Element at Sixth Index : E
Contents of al : [A, B, C, B, D, A, E]
ArrayList contain D : true
ArrayList contain F : false
Test your knowledge

Question: Consider the following code:

Computer code
public class ArrayListDemo {
		public static void main(String[] args) {
	
		ArrayList al = new ArrayList();

		al.add("A");
		al.add("B");
		al.add("C");
		al.add("E");
		al.add("F");
	
		al.remove(2);
		al.remove("F");
		
		al.set(1, "G");
		al.add("H");
		al.set(3, "I");
		System.out.println("Size of al : " + al.size());
		System.out.println("Contents of al : " + al);

	}
  }


In the example above, what is output?

Answer
Computer code
Size of al : 4
Contents of al : [A, G, E, I]

Some more ArrayList methods:

Method Description
Object clone() Returns a shallow copy of this ArrayList.
Object[] toArray() Returns an array containing all of the elements in this list in the correct order. Throws NullPointerException if the specified array is null.
void trimToSize() Trims the capacity of this ArrayList instance to be the list's current size.
void ensureCapacity(int minCapacity) Increases the capacity of this ArrayList instance, if necessary, to ensure that it can hold at least the number of elements specified by the minimum capacity argument.
protected void removeRange(int fromIndex, int toIndex) Removes from this List all of the elements whose index is between fromIndex, inclusive and toIndex, exclusive.


Map

Aside from the java.util.Collection interface, the Java JDK has the java.util.Map interface as well. It is sometimes also called an Associated Array or a Dictionary. A map defines key value mappings. Implementations of the Map interface do not contain collections of objects. Instead they contain collections of key->value mappings. It can be thought of as an array where the index doesn't need to be an integer.

Example Code section 5.17: Use of a map.
1 import java.util.Map;
2 import java.util.Hashtable;
3 ...
4 Map map = new Hashtable();
5 ...
6 map.put(key, value);

Use the Map interface if you need to keep related objects together in a Map where you can:

  • Access an element by a key object
  • Map one object to other


Figure 5.6: Map Interfaces.
Java map interfaces.svg


java.util.Map<K,V> 
maps keys to values. A map cannot contain duplicate keys; each key can map to at most one value. The Map interface provides three collection views, which allow a map's contents to be viewed as a set of keys, collection of values, or set of key-value mappings. The key is usually a non-mutable object. The value object however can be a mutable object.
java.util.SortedMap<K,V> 
same as the Map interface, plus the keys in the Map are sorted.

In the above example, the same operations are made with two different map implementations:

Computer code Code listing 5.4: MapImplementations.java
 1 import java.util.LinkedHashMap;
 2 import java.util.Map;
 3 import java.util.TreeMap;
 4 
 5 /**
 6  * Compare the map implementations.
 7  *
 8  * @author xxx
 9  */
10 public class MapImplementations {
11 
12   /**
13    * Compare the map implementations.
14    * @param args The execution parameters.
15    */
16   public static void main(String[] args) {
17     processMap(new LinkedHashMap<String, Integer>());
18 
19     processMap(new TreeMap<String, Integer>());
20   }
21 
22   /**
23    * Use a map:
24    * 1. Fill the map with key-> value.
25    * 2. Print all the keys.
26    *
27    * @param map The used map.
28    */
29   public static void processMap(Map<String, Integer> map) {
30     System.out.println("Process the map");
31     map.put("3", new Integer(3));
32     map.put("2", new Integer(2));
33     map.put("1", new Integer(1));
34 
35     for (String key : map.keySet()) {
36       System.out.println(key);
37     }
38   }
39 }
Standard input or output Console for Code listing 5.4
Process the map
3
2
1
Process the map
1
2
3

We see that only the TreeMap has sorted the keys. Beware of the generics. The Map interface is tricky. The methods get() and remove() are not generic. This means that you must be careful of the type of the key:

Example Code section 5.18: Tricky generics.
 1 Map<Integer, String> map = new TreeMap<Integer, String>();
 2 
 3 map.put(new Integer(1), "Watch");
 4 map.put(new Integer(2), "out");
 5 map.put(new Integer(3), "!");
 6 
 7 map.remove("2");
 8 
 9 for (String value : map.values()) {
10   System.out.println(value);
11 }
Standard input or output Console for Code section 5.18
Watch
out
!

The remove() call has done nothing because "2" is a String, not an Integer so no key and value has been found and removed.

Map Classes

The Map interface has the following implementations:


Figure 5.7: Map class diagram.
Java map implementation.svg


java.util.TreeMap<E>
guarantees that the map will be in ascending key order, sorted according to the natural order for the key's class, not-synchronized.
java.util.Hashtable<E> 
Synchronized, null can not be used as key
java.util.HashMap<E> 
is roughly equivalent to Hashtable, except that it is unsynchronized and permits nulls
java.util.concurrent.ConcurrentHashMap 
same as Hashtable, plus retrieval operations (including get) generally do not block, so may overlap with update operations (including put and remove).
java.util.WeakHashMap<E> 
entry in a WeakHashMap will automatically be removed when its key is no longer in ordinary use. Non-synchronized.
java.util.LinkedHashMap<E> 
This linked list defines the iteration ordering, which is normally the order in which keys were first inserted into the map (first insertion-order). Note that insertion order is not affected if a key is re-inserted into the map.
java.util.IdentityHashMap 
This class implements the Map interface with a hash table, using reference-equality in place of object-equality when comparing keys (and values). In other words, in an IdentityHashMap, two keys k1 and k2 are considered equal if and only if (k1==k2). (In normal Map implementations (like HashMap) two keys k1 and k2 are considered equal if and only if (k1==null ? k2==null : k1.equals(k2)).) Not-synchronized.
java.util.EnumMap 
All of the keys in an enum map must come from a single enum type that is specified, explicitly or implicitly, when the map is created. Enum maps are represented internally as arrays. This representation is extremely compact and efficient. Not-synchronized.

Thread safe maps

The following table lists all the synchronized map classes:

synchronized non-synchronized
java.util.TreeMap
java.util.Hashtable

java.util.concurrent.ConcurrentHashMap

java.util.HashMap
java.util.LinkedHashMap
java.util.IdentityHashMap
java.util.EnumMap



Comparing Objects

In Java, we can distinguish two kinds of equality.

  • Object reference equality: when two object references point to the same object.
  • Object value equality: when two separate objects happen to have the same values/state.

If two objects are equal in reference, they are equal in value too.

Comparing for reference equality

The == operator can be used to check if two object references point to the same object.

Example Code section 5.19: Reference equality.
1 if (objRef1 == objRef2) {
2     // The two object references point to the same object
3 }

Comparing for value equality

To be able to compare two Java objects of the same class the boolean equals(Object obj) method must be overriden and implemented by the class.

The implementor decides which values must be equal to consider two objects to be equal. For example in the below class, the name and the address must be equal but not the description.

Computer code Code listing 5.5: Customer.java
 1 public class Customer {
 2     private String name;
 3     private String address;
 4     private String description;
 5     // ...
 6     public boolean equals(Object obj) {
 7         if (this == obj) {
 8             return true;
 9         } else if (obj == null) {
10             return false;
11         } else if (obj instanceof Customer) {
12             Customer cust = (Customer) obj;
13             if ((cust.getName() == null && name == null) ||
14                 (cust.getName().equals(name) && ((cust.getAddress() == null && address == null)
15                 || cust.getAddress().equals(address))) {
16                 return true;
17             }
18         }
19         return false;
20     }
21 
22 }

After the equals() method is overriden, two objects from the same class can be compared like this:

Example Code section 5.20: Method usage.
1 Customer cust1 = new Customer();
2 Customer cust2 = new Customer();
3 //...
4 if (cust1.equals(cust2)) {
5     // Two Customers are equal, by name and address
6 }

Note that equal objects must have equal hash codes. Therefore, when overriding the equals method, you must also override the hashCode method. Failure to do so violates the general contract for the hashCode method, and any classes that use the hash code, such as HashMap will not function properly.

Sorting/Ordering

In Java, there are several existing methods that already sort objects from any class like Collections.sort(List<T> list). However, Java needs to know the comparison rules between two objects. So when you define a new class and want the objects of your class to be sortable, you have to implement the Comparable and redefine the compareTo(Object obj) method.

int compareTo(T o) 
Compares two objects and return an integer:
  • A negative integer means that the current object is before the parameter object in the natural ordering.
  • Zero means that the current object and the parameter object are equal.
  • A positive integer means that the current object is after the parameter object in the natural ordering.

Let's say that the name is more important than the address and the description is ignored.

Computer code Code listing 5.6: SortableCustomer.java
 1 public class SortableCustomer implements Comparable<SortableCustomer> {
 2     private String name;
 3     private String address;
 4     private String description;
 5     // ...
 6     public int compareTo(SortableCustomer anotherCustomer) {
 7         if (name.compareTo(anotherCustomer.getName()) == 0) {
 8             return address.compareTo(anotherCustomer.getAddress();
 9         } else {
10             return name.compareTo(anotherCustomer.getName();
11         }
12     }
13 
14 }

Objects that implement this interface can be used as keys in a sorted map or elements in a sorted set, without the need to specify a comparator.

The natural ordering for a class C is said to be consistent with equals if and only if e1.compareTo((Object) e2) == 0 has the same boolean value as e1.equals((Object) e2) for every e1 and e2 of class C. Note that null is not an instance of any class, and e.compareTo(null) should throw a NullPointerException even though e.equals(null) returns false.

It is strongly recommended (though not required) that natural orderings be consistent with equals. This is because sorted sets (and sorted maps) without explicit comparators behave "strangely" when they are used with elements (or keys) whose natural ordering is inconsistent with equals. In particular, such a sorted set (or sorted map) violates the general contract for set (or map), which is defined in terms of the equals method.

Change Sorting/Ordering

Sometimes we may want to change the ordering of a collection of objects from the same class. We may want to order descending or ascending order. We may want to sort by name or by address.

We need to create a class for each way of ordering. It has to implement the Comparator interface.

Since Java 5.0, the Comparator interface is generic; that means when you implement it, you can specify what type of objects your comparator can compare.

Computer code Code listing 5.7: CustomerComparator.java
1 public class CustomerComparator implements Comparator<Customer> {
2     public int compare(Customer cust1, Customer cust2) {
3         return cust1.getName().compareTo(cust2.getName());
4     }
5 }

The above class then can be associated with a SortedSet or other collections that support sorting.

Example Code section 5.21: Comparator usage.
1 Collection<Customer> orderedCustomers = new TreeSet<Customer>(new CustomerComparator());

Using the Iterator the orderedCustomers collection can be iterated in order of sorted by name.

A List can be sorted by the Collections' sort method.

Example Code section 5.22: Customized comparison.
1 java.util.Collections.sort(custList, new CustomerComparator());

Sorts the specified list according to the order induced by the specified comparator. All elements in the list must be mutually comparable using the specified comparator.

An array of objects can also be sorted with the help of a Comparator.

Example Code section 5.23: Array sorting.
1 SortableCustomer[] customerArray;
2 //...
3 java.util.Arrays.sort(customerArray, new CustomerComparator());

Sorts the specified array of Customer objects (customerArray) according to the order induced by the specified comparator. All elements in the array must be mutually comparable by the specified comparator.



Exceptions

The ideal time to catch an error is at compile time, before you even try to run the program. However, not all errors can be detected at compile time. The rest of the problems must be handled at run time through some formality that allows the originator of the error to pass appropriate information to a recipient who will know how to handle the difficulty properly.

Improved error recovery is one of the most powerful ways that can increase the robustness of your code. Error recovery is a fundamental concern for every program you write, but it's especially important in Java, where one of the primary goals is to create program components for others to use. To create a robust system, each component must be robust. By providing a consistent error-reporting model using exceptions, Java allows components to reliably communicate problems to client code.

Flow of code execution

In Java, there are two main flows of code executions.

  • Normal main sequential code execution, the program doing what it meant to accomplish.
  • Exception handling code execution, the main program flow was interrupted by an error or some other condition that prevent the continuation of the normal main sequential code execution.
Exception 
Exceptions are Java's way of error handling. Whenever an unexpected condition occurs, an exception can be thrown with an exception object as a parameter. It means that the normal program control flow stops and the search for a catch block begins. If that is not found at the current method level the search continues at the caller method level, until a matching catch block is found. If none is found the exception will be handled by the JVM, and usually the java program terminates.
When a catch "matching" block is found, that block will be executed, the exception object is passed to the block as a parameter. Then normal program execution continues after the catch block. See Java exception handling syntax.
Exception Object 
This is the object that is "thrown" as a parameter from the error, and passed to the catch block. Exception object encapsulates the information about the error's location and its nature. All Exception objects must be inherited from the java.lang.Throwable. See the UML diagram below.
Figure 6.1: Java exception classes
Java exception classes.svg


Matching rule 
A thrown exception object can be caught by the catch keyword and specifying the exception object's class or its super-class.
Naming convention 
It is good practice to add Exception to all exception classes. Also the name of the exception should be meaningful, should represent the problem. For example CustomerNotFoundException indicate that customer was not found.



Throwing and Catching Exceptions

Language compilers are adept at pointing out most of the erroneous code in a program, however there are some errors that only become apparent when the program is executed. Consider the code listing 6.1; here, the program defines a method divide that does a simple division operation taking two integers as parameter arguments and returning the result of their division. It can safely be assumed that when the divide(4, 2) statement is called, it would return the number 2. However, consider the next statement, where the program relies upon the provided command line arguments to generate a division operation. What if the user provides the number zero (0) as the second argument? We all know that division by zero is impossible, but the compiler couldn't possibly have anticipated the user providing zero as an argument.

Computer code Code listing 6.1: SimpleDivisionOperation.java
 1 public class SimpleDivisionOperation {
 2   public static void main(String[] args) {
 3     System.out.println(divide(4, 2));
 4     if (args.length > 1) {
 5       int arg0 = Integer.parseInt(args[0]);
 6       int arg1 = Integer.parseInt(args[1]);
 7       System.out.println(divide(arg0, arg1));
 8     }
 9   }
10 
11   public static int divide(int a, int b) {
12     return a / b;
13   }
14 }
Standard input or output Output for Code listing 6.1
$ java SimpleDivisionOperation 1 0
2
Exception in thread "main" java.lang.ArithmeticException: / by zero
     at SimpleDivisionOperation.divide(SimpleDivisionOperation.java:12)
     at SimpleDivisionOperation.main(SimpleDivisionOperation.java:7)

Such exceptional code that results in erroneous interpretations at program runtime usually results in errors that are called exceptions in Java. When the Java interpreter encounters an exceptional code, it halts execution and displays information about the error that occurs. This information is known as a stack trace. The stack trace in the above example tells us more about the error, such as the thread — "main" — where the exception occurred, the type of exception — java.lang.ArithmeticException, a comprehensible display message — / by zero, and the exact methods and the line numbers where the exception may have occurred.

Exception object

The preceding exception could have been created explicitly by the developer as it is the case in the following code:

Computer code Code listing 6.2: SimpleDivisionOperation.java
 1 public class SimpleDivisionOperation {
 2   public static void main(String[] args) {
 3     System.out.println(divide(4, 2));
 4     if (args.length > 1) {
 5       // Convert a string to an integer
 6       int arg0 = Integer.parseInt(args[0]);
 7       int arg1 = Integer.parseInt(args[1]);
 8       System.out.println(divide(arg0, arg1));
 9     }
10   }
11 
12   public static int divide(int a, int b) {
13     if (b == 0) {
14       throw new ArithmeticException("You can\'t divide by zero!");       
15     } else {
16       return a / b;
17     }
18   }
19 }
Standard input or output Output for Code listing 6.2
$ java SimpleDivisionOperation 1 0
2
Exception in thread "main" java.lang.ArithmeticException: You can't divide by zero!
at SimpleDivisionOperation.divide(SimpleDivisionOperation.java:14)
at SimpleDivisionOperation.main(SimpleDivisionOperation.java:7)

Note that when b equals zero, there is no return value. Instead of a java.lang.ArithmeticException generated by the Java interpreter itself, it is an exception created by the coder. The result is the same. It shows you that an exception is an object. Its main particularity is that it can be thrown. An exception object must inherit from java.lang.Exception. Standard exceptions have two constructors:

  1. The default constructor; and,
  2. A constructor taking a string argument so that you can place pertinent information in the exception.
Example Code section 6.1: Instance of an exception object with the default constructor.
1 new Exception();
Example Code section 6.2: Instance of an Exception object by passing string in constructor.
1 new Exception("Something unexpected happened");

This string can later be extracted using various methods, as you can see in the code listing 6.2.

You can throw any type of Throwable object using the keyword throw. It interrupts the method. Anything after the throw statement would not be executed, unless the thrown exception is handled. The exception object is not returned from the method, it is thrown from the method. That means that the exception object is not the return value of the method and the calling method can be interrupted too and so on and so on...

Typically, you'll throw a different class of exception for each different type of error. The information about the error is represented both inside the exception object and implicitly in the name of the exception class, so someone in the bigger context can figure out what to do with your exception. Often, the only information is the type of exception, and nothing meaningful is stored within the exception object.

Oracle standard exception classes

The box 6.1 below talks about the various exception classes within the java.lang package.

Box 6.1: The Java exception classes

Throwable 
The Throwable class is the superclass of all errors and exceptions in the Java language. Only objects that are instances of this class (or one of its subclasses) are thrown by the Java Virtual Machine or can be thrown by the Java throw statement.
A throwable contains a snapshot of the execution stack of its thread at the time it was created. It can also contain a message string that gives more information about the error. Finally, it can contain a cause: another throwable that caused this throwable to get thrown. The cause facility was added in release 1.4. It is also known as the chained exception facility, as the cause can, itself, have a cause, and so on, leading to a "chain" of exceptions, each caused by another.
Error 
An Error indicates serious problems that a reasonable application should not try to handle. Most such errors are abnormal conditions.
Exception 
The class Exception and its subclasses are a form of Throwable that indicates conditions that a reasonable application might want to handle. Also this is the class that a programmer may want to extend when adding business logic exceptions.
RuntimeException 
RuntimeException is the superclass of those exceptions that can be thrown during the normal operation of the Java Virtual Machine. A method is not required to declare in its throws clause any subclasses of RuntimeException that might be thrown during the execution of the method but not caught.
Figure 6.2: The exception classes and their inheritance model in the JCL.
Java exception classes.svg

try/catch statement

By default, when an exception is thrown, the current method is interrupted, the calling method is interrupted too and so on till the main method. A thrown exception can also be caught using a try/catch statement. Below is how a try/catch statement works:

Example Code section 6.3: Division into a try block.
 1 int a = 4;
 2 int b = 2;
 3 int result = 0;
 4 try {
 5   int c = a / b;
 6   result = c;
 7 } catch(ArithmeticException ex) {
 8   result = 0;
 9 }
10 return result;

The executed code lines have been highlighted. When no exception is thrown, the method flow executes the try statement and not the catch statement.

Example Code section 6.4: Catching 'division by zero' errors.
 1 int a = 4;
 2 int b = 0;
 3 int result = 0;
 4 try {
 5   int c = a / b;
 6   result = c;
 7 } catch(ArithmeticException ex) {
 8   result = 0;
 9 }
10 return result;

As there is a thrown exception at line 5, the line 6 is not executed, but the exception is caught by the catch statement so the catch block is executed. The following code is also executed. Note that the catch statement takes an exception as parameter. There is a third case: when the exception is not from the same class as the parameter:

Example Code section 6.5: Uncaught exception.
 1 int a = 4;
 2 int b = 0;
 3 int result = 0;
 4 try {
 5   int c = a / b;
 6   result = c;
 7 } catch(NullPointerException ex) {
 8   result = 0;
 9 }
10 return result;

It is as if there is no try/catch statement. The exception is thrown to the calling method.

catch blocks

A try/catch statement can contain several catch blocks, to handle different exceptions in different ways. Each catch block must take a parameter of a different throwable class. A thrown object may match several catch block but only the first catch block that matches the object will be executed. A catch-block will catch a thrown exception if and only if:

  • the thrown exception object is the same as the exception object specified by the catch-block.
  • the thrown exception object is the subtype of the exception object specified by the catch-block.

This means that the catch block order is important. As a consequence, you can't put a catch block that catches all the exception (which take a java.lang.Exception as parameter) before a catch block that catches a more specific exception as the second block could never be executed.

Example Code section 6.6: Exception handling with catch blocks.
 1 try {
 2   // Suppose the code here throws any exceptions,
 3   // then each is handled in a separate catch block.
 4 
 5   int[] tooSmallArray = new int[2];
 6   int outOfBoundsIndex = 10000;
 7   tooSmallArray[outOfBoundsIndex] = 1;
 8 
 9   System.out.println("No exception thrown.");
10 } catch(NullPointerException ex) {
11   System.out.println("Exception handling code for the NullPointerException.");
12 } catch(NumberFormatException ex) {
13   System.out.println("Exception handling code for the NumberFormatException.");
14 } catch(ArithmeticException | IndexOutOfBoundsException ex) {
15   System.out.println("Exception handling code for ArithmeticException"
16     + " or IndexOutOfBoundsException.");
17 } catch(Exception ex) {
18   System.out.println("Exception handling code for any other Exception.");
19 }
Standard input or output Output for Code section 6.6
Exception handling code for ArithmeticException or IndexOutOfBoundsException.

At line 14, we use a multi-catch clause. It is available since the JDK 7. This is a combination of several catch clauses and let's you handle exceptions in a single handler while also maintaining their types. So, instead of being boxed into a parent Exception super-class, they retain their individual types.

You can also use the java.lang.Throwable class here, since Throwable is the parent class for the application-specific Exception classes. However, this is discouraged in Java programming circles. This is because Throwable happens to also be the parent class for the non-application specific Error classes which are not meant to be handled explicitly as they are catered for by the JVM itself.

finally block

A finally block can be added after the catch blocks. A finally block is always executed, even when no exception is thrown, an exception is thrown and caught, or an exception is thrown and not caught. It's a place to put code that should always be executed after an unsafe operation like a file close or a database disconnection. You can define a try block without catch block, however, in this case, it must be followed by a finally block.

Example of handling exceptions

Let's examine the following code:

Warning Code section 6.7: Handling exceptions.
 1 public void methodA() throws SomeException {
 2     // Method body
 3 }
 4 
 5 public void methodB() throws CustomException, AnotherException {
 6     // Method body
 7 }
 8 
 9 public void methodC() {
10     methodB();
11     methodA();
12 }

In the code section 6.7, methodC is invalid. Because methodA and methodB pass (or throw) exceptions, methodC must be prepared to handle them. This can be handled in two ways: a try-catch block, which will handle the exception within the method and a throws clause which would in turn throw the exception to the caller to handle. The above example will cause a compilation error, as Java is very strict about exception handling. So the programmer is forced to handle any possible error condition at some point.

A method can do two things with an exception: ask the calling method to handle it by the throws declaration or handle the exception inside the method by the try-catch block.

To work correctly, the original code can be modified in multiple ways. For example, the following:

Example Code section 6.8: Catching and throwing exceptions.
1 public void methodC() throws CustomException, SomeException {
2   try {
3     methodB();
4   } catch(AnotherException e) {
5     // Handle caught exceptions.
6   }
7   methodA();
8 }

The AnotherException from methodB will be handled locally, while CustomException and SomeException will be thrown to the caller to handle it. Most of the developers are embarrassed when they have to choose between the two options. This type of decision should not be taken at development time. If you are a development team, it should be discussed between all the developers in order to have a common exception handling policy.

Keyword references



Checked Exceptions

A checked exception is a type of exception that must be either caught or declared in the method in which it is thrown. For example, the java.io.IOException is a checked exception. To understand what is a checked exception, consider the following code:

Warning Code section 6.9: Unhandled exception.
1 public void ioOperation(boolean isResourceAvailable) {
2   if (!isResourceAvailable) {
3     throw new IOException();
4   }
5 }

This code won't compile because it can throw a checked exception. The compilation error can be resolved in either of two ways: By catching the exception and handling it, or by declaring that the exception can be thrown using the throws keyword.

Example Code section 6.10: Catching an exception.
1 public void ioOperation(boolean isResourceAvailable) {
2   try {
3     if (!isResourceAvailable) {
4       throw new IOException();
5     }
6   } catch(IOException e) {
7     // Handle caught exceptions.
8   }
9 }
Example Code section 6.11: Declaring an exception.
1 public void ioOperation(boolean isResourceAvailable) throws IOException {
2   if (!isResourceAvailable) {
3     throw new IOException();
4   }
5 }

In the Java class hierarchy, an exception is a checked exception if it inherits from java.lang.Throwable, but not from java.lang.RuntimeException or java.lang.Error. All the application or business logic exceptions should be checked exceptions.

It is possible that a method declares that it can throw an exception, but actually it does not. Still, the caller has to deal with it. The checked exception declaration has a domino effect. Any methods that will use the previous method will also have to handle the checked exception, and so on.

So the compiler for the Java programming language checks, at compile time, that a program contains handlers for all application exceptions, by analyzing each method body. If, by executing the method body, an exception can be thrown to the caller, that exception must be declared. How does the compiler know whether a method body can throw an exception? That is easy. Inside the method body, there are calls to other methods; the compiler looks at each of their method signature, what exceptions they declared to throw.

Why Force Exception Handling?

This may look boring to the developer but it forces them to think about all the checked exceptions and increase the code quality. This compile-time checking for the presence of exception handlers is designed to make the application developer life easier. To debug whether a particular thrown exception has a matching catch would be a long process. In conventional languages like C, and C++, a separate error handling debugging were needed. In java we can be sure that when an application exception is thrown, that exception somewhere in the program is handled. In C, and C++, that has to be tested. In Java that does not need to be tested, so the freed up time can be used for more meaningful testing, testing the business features.

What Exceptions can be Declared when Overriding a Method?

The checked exception classes specified after the throws keyword are part of the contract between the implementer and user. An overriding method can declare the same exceptions, subclasses or no exceptions.

What Exceptions can be Declared when Implementing an Interface?

When interfaces are involved, the implementation declaration must have a throws-clause that is compatible with the interface declarations.



Unchecked Exceptions

Unchecked, uncaught or runtime exceptions are exceptions that can be thrown without being caught or declared:

Example Code section 6.12: Throwing an exception without declaring it or catching it.
1 public void futureMethod() {
2   throw new RuntimeException("This method is not yet implemented");
3 }

...however, you can still declare and catch such exceptions. Runtime exceptions are not business exceptions. They are usually related to hard-coded issues like data errors, arithmetic overflow, divide by zero etc. In other words, errors that can't be worked around nor anticipated. The most famous (and feared) runtime exception is the NullPointerException.

A runtime exception must be or inherit from the RuntimeException class or the Error class.

Sometime it is desirable to catch all exceptions for logging purposes, then throw them back in. For example, in servlet programming when an application server calls the server getLastModified(), we want to monitor that no exceptions happened during the serving of the request. The application has its own logging separate from the server logging so the runtime exceptions would just go through without being detected by the application. The following code checks all exceptions, logs them and throws them back again.

Example Code section 6.13: Logging an exception.
 1 public long getLastModified(HttpServletRequest req) {
 2   try {
 3     ...
 4     return getTimeStamp();
 5     ...
 6   } catch(RuntimeException e) {
 7     log.error("Error during handling post request", e);
 8 
 9     throw e;
10   }
11 }

In the above code, all business logic exception are handled in the getTimeStamp() method. Runtime exceptions are caught for logging purposes, and then thrown back to the server to be handled.



Preventing NullPointerException

NullPointerException is a RuntimeException. In Java, a special null value can be assigned to an object reference. NullPointerException is thrown when an application attempts to use an object reference that has the null value. These include:

  • Calling an instance method on the object referred by a null reference.
  • Accessing or modifying an instance field of the object referred by a null reference.
  • If the reference type is an array type, taking the length of a null reference.
  • If the reference type is an array type, accessing or modifying the slots of a null reference.
  • If the reference type is a subtype of Throwable, throwing a null reference.

Applications should throw instances of this class to indicate other illegal uses of the null object.

Example Code section 6.13: Null pointer.
1 Object obj = null;
2 obj.toString();  // This statement will throw a NullPointerException

The above code shows one of the pitfalls of Java and the most common source of bugs. No object is created and the compiler does not detect it. NullPointerException is one of the most common exceptions thrown in Java.

Why do we need null?

The reason we need it is because many times we need to create an object reference before the object itself is created. Object references cannot exist without a value, so we assign the null value to it.

Example Code section 6.14: Non-instantiated declared object.
1 public Person getPerson(boolean isWoman) {
2   Person person = null;
3   if (isWoman) {
4     person = createWoman();
5   } else {
6     person = createMan();
7   }
8   return person;
9 }

In code section 6.14 we want to create the Person inside the if-else, but we also want to return the object reference to the caller, so we need to create the object reference outside of the if-else, because of the scoping rule in Java. Incorrect error-handling and poor contract design can be a pitfall with any programming language. This is also true for Java.

Now we will describe how to prevent NullPointerException. We do not describe general techniques for how you should program Java, we just hope to make you more aware of null values, and to be more careful about generating them yourself.

This list is not complete — there are no rules for preventing NullPointerException entirely in Java, because the standard libraries have to be used, and they can cause NullPointerExceptions. Also, it is possible to observe an uninitialized final field in Java, so you can't even treat a final field as being completely trusted during the object's creation.

A good approach is to learn how to deal with NullPointerExceptions first, and become competent with that. These suggestions will help you to cause less NullPointerExceptions, but they don't replace the need to know about NullPointerExceptions.

Comparing string variable with a string literal

When you compare a variable with a string literal, most of people would do that this way:

Example Code section 6.15: Bad comparison.
1 if (state.equals("OK")) {
2   ...
3 }

Always put the string literal first:

Example Code section 6.16: Better comparison.
1 if ("OK".equals(state)) {
2   ...
3 }

If the state variable is null, you get a NullPointerException in the first example, but not in the second one.

Minimize the use of the keyword 'null' in assignment statements

This means not doing things like:

Example Code section 6.17: Declaring an exception.
 1 String s = null;
 2 while (something) {
 3     if (something2) {
 4         s = "yep";
 5     }
 6 }
 7 
 8 if (s != null) {
 9     something3(s);
10 }

You can replace this with:

Example Code section 6.18: Declaring an exception.
1 boolean done = false;
2 
3 while (!done && something) {
4     if (something2) {
5        done = true;
6        something3("yep");
7     }
8 }

You might also consider replacing null with "" in the first example, but default values bring about bugs caused by default values being left in place. A NullPointerException is actually better, as it allows the runtime to tell you about the bug, rather than just continue with a default value.

Minimize the use of the new Type[int] syntax for creating arrays of objects

An array created using new Object[10] has 10 null pointers. That's 10 more than we want, so use collections instead, or explicitly fill the array at initialization with:

Example Code section 6.19: Declaring an exception.
1 Object[] objects = {"blah", 5, new File("/usr/bin")};

or:

Example Code section 6.20: Declaring an exception.
1 Object[] objects;
2 objects = new Object[]{"blah", 5, new File("/usr/bin")};

Check all references obtained from 'untrusted' methods

Many methods that can return a reference can return a null reference. Make sure you check these. For example:

Example Code section 6.21: Declaring an exception.
1 File file = new File("/etc");
2 File[] files = file.listFiles();
3 if (files != null) {
4     stuff
5 }

File.listFiles() can return null if /etc is not a directory.

You can decide to trust some methods not to return null, if you like, but that's an assumption you're making. Some methods that don't specify that they might return null, actually do, instead of throwing an exception.

For each loop trap

Beware if you loop on an array or a collection in a for each loop.

Example Code section 6.22: Visit a collection.
1 Collection<Integer> myNumbers = buildNumbers();
2 for (Integer myNumber : myNumbers) {
3   System.out.println(myNumber);
4 }

If the object is null, it does not just do zero loops, it throws a null pointer exception. So don't forget this case. Add an if statement or return empty collections:

Example Code section 6.23: Visit a collection safety.
1 Collection<Integer> myNumbers = buildNumbers();
2 if (myNumbers != null) {
3   for (Integer myNumber : myNumbers) {
4     System.out.println(myNumber);
5   }
6 }

External tools

There are tools like FindBugs that parse your code and warn you about potential bugs. Most of the time, these tools detect possible null pointers.



Stack trace

Stack Trace is a list of method calls from the point when the application was started to the point where the exception was thrown. The most recent method calls are at the top.

Computer code Code listing 6.3: StackTraceExample.java
 1 public class StackTraceExample {
 2   public static void main(String[] args) {
 3     method1();
 4   }
 5 
 6   public static void method1() {
 7     method11();
 8   }
 9 
10   public static void method11() {
11     method111();
12   }
13 
14   public static void method111() {
15     throw new NullPointerException("Fictitious NullPointerException");
16   }
17 }
Standard input or output Output for Code listing 6.3
Exception in thread "main" java.lang.NullPointerException: Fictitious NullPointerException
at StackTraceExample.method111(StackTraceExample.java:15)
at StackTraceExample.method11(StackTraceExample.java:11)
at StackTraceExample.method1(StackTraceExample.java:7)
at StackTraceExample.main(StackTraceExample.java:3)

The stack trace can be printed to the standard error by calling the public void printStackTrace() method of an exception.

From Java 1.4, the stack trace is encapsulated into an array of a java class called java.lang.StackTraceElement. The stack trace element array returned by Throwable.getStackTrace() method. Each element represents a single stack frame. All stack frames except for the one at the top of the stack represent a method invocation. The frame at the top of the stack represents the execution point at which the stack trace was generated. Typically, this is the point at which the throwable corresponding to the stack trace was created.

A stack frame represents the following information:

Example Code section 6.24: Stack frame.
1 public StackTraceElement(String declaringClass,
2                          String methodName,
3                          String fileName,
4                          int lineNumber);

Creates a stack trace element representing the specified execution point.

Converting the stack trace into string

Many times for debugging purposes, we'd like to convert the stack trace to a String so we can log it to our log file.

The following code shows how to do that:

Example Code section 6.25: Save the stack trace.
 1 import java.io.StringWriter;
 2 import java.io.PrintWriter;
 3 
 4 ...
 5 
 6   Exception e = new NullPointerException();
 7 
 8   StringWriter outError = new StringWriter();
 9   e.printStackTrace(new PrintWriter(outError));
10   String errorString = outError.toString();
11 
12   // Do whatever you want with the errorString



Nesting Exceptions

When an exception is caught, the exception contains the stack-trace, which describes the error and shows where the exception happened (i.e. where the problem is and where the application programmer should look to fix the problem). Sometimes it is desirable to catch an exception and throw another exception. If the new exception keeps a reference to the first exception, the first exception is called a nesting exception.

Computer code Code listing 6.4: NestingExceptionExample.java
 1 public class NestingExceptionExample {
 2  
 3   public static void main(String[] args) throws Exception {
 4     Object[] localArgs = (Object[]) args;
 5    
 6     try {
 7       Integer[] numbers = (Integer[]) localArgs;
 8     } catch (ClassCastException originalException) {
 9       Exception generalException = new Exception(
10         "Horrible exception!",
11         originalException);
12       throw generalException;
13     }
14   }
15 }
Standard input or output Output for Code listing 6.4
Exception in thread "main" java.lang.Exception: Horrible exception!
at NestingExceptionExample.main(NestingExceptionExample.java:9)
Caused by: java.lang.ClassCastException: [Ljava.lang.String; incompatible with [Ljava.lang.Integer;
at NestingExceptionExample.main(NestingExceptionExample.java:7)

The above code is an example of a nesting exception. When the Exception is thrown, by passing in the ClassCastException object reference as a parameter, the ClassCastException is nested in the newly created Exception, its stack-trace is appended together. When the Exception is caught, its stack-trace contains the original ClassCastException's stack-trace.

This is a kind of exception conversion, from one exception to another. For example, calling a remote object using RMI, the calling method has to deal with RemoteException which is thrown if something is wrong during the communication. From the application point of view, RemoteException has no meaning, it should be transparent to the application that a remote object was used or not. So the RemoteException should be converted to an application exception.

This conversion can also hide where the error is originated. The stack-trace starts when the exception is thrown. So when we catch and throw a new exception, the stack-trace starts at when the new exception was thrown, losing the original stack-trace. This was true with the earlier version of Java (before 1.4). Since then, so called cause facility capabilities were built in the Throwable class.

A throwable contains a snapshot of the execution stack of its thread at the time it was created. It can also contain a message string that gives more information about the error. Finally, it can contain a cause: another throwable that caused this throwable to get thrown. The cause facility is also known as the chained exception facility, as the cause can, itself, have a cause, and so on, leading to a "chain" of exceptions, each caused by another.

A cause can be associated with a throwable in two ways: via a constructor that takes the cause as an argument, or via the initCause(Throwable) method. New throwable classes that wish to allow causes to be associated with them should provide constructors that take a cause and delegate (perhaps indirectly) to one of the Throwable constructors that takes a cause. For example:

Example Code section 6.26: Chaining-aware constructor.
1 try {
2     lowLevelOp();
3 } catch (LowLevelException le) {
4     throw new HighLevelException(le);
5 }

Because the initCause method is public, it allows a cause to be associated with any throwable, even a "legacy throwable" whose implementation predates the addition of the exception chaining mechanism to Throwable. For example:

Example Code section 6.27: Legacy constructor.
1 try {
2     lowLevelOp();
3 } catch (LowLevelException le) {
4     throw (HighLevelException) new HighLevelException().initCause(le);
5 }

Further, as of release 1.4, many general purpose Throwable classes (for example Exception, RuntimeException, Error) have been retrofitted with constructors that take a cause. This was not strictly necessary, due to the existence of the initCause method, but it is more convenient and expressive to delegate to a constructor that takes a cause.

By convention, class Throwable and its subclasses have two constructors, one that takes no arguments and one that takes a String argument that can be used to produce a detail message. Further, those subclasses that might likely have a cause associated with them should have two more constructors, one that takes a Throwable (the cause), and one that takes a String (the detail message) and a Throwable (the cause).



Concurrent Programming

In computer programming, an application program runs in a certain process of the CPU. Every statement that is then executed within the program is actually being executed in that process. In essence, when a statement is being executed, the CPU focuses all its attention on that particular statement and for the tiniest fraction of a second puts everything else on hold. After executing that statement, the CPU executes the next statement and so forth.

But consider for a moment that the execution of a particular statement is expected to take a considerable amount of time. You do not want to keep the CPU on halt until the statement gets executed and done with; you would want the CPU to continue with some other application process and resume the current application as smoothly as possible after its statement is executed. It can only be possible if you can run several processes simultaneously, such that when one process is executing a statement that is expected to take some time, another process in the queue would continue doing other things and so on. Such a principle of programming is called concurrent programming.

Throughout this chapter, we will be taking a look at concurrent programming constructs present in the Java programming language.



Threads and Runnables

CPUs for any computer are designed to execute one task at any given time, yet we run multiple applications side-by-side and everything works in perfect congruence. It's not just because CPUs are extremely fast in performing calculations, it's because CPUs use a clever device of dividing their time amongst various tasks. Each application or task that is invoked on a computer gets associated with the CPU in the form of a process. A CPU therefore manages various processes, and jumps back and forth amongst each process giving it a fraction of its time and processing capability. This happens so fast that to a normal computer user it presents with the illusion of processes being run simultaneously. This capability of the CPU to divide its time amongst processes is called multitasking.

So, if we run a Java application on a computer, we are effectively creating a process with the CPU that gets a fraction of the CPU's time. In Java parlance, this main process gets called the daemon process or the daemon thread. But, Java goes one step further. It allows programmers to divide this daemon thread into several multiple threads which get executed simultaneously (much like a CPU) hence providing a Java application with a finer multitasking capability called multithreading.

In this section, we will take a look at what threads are and how multithreading is implemented within a Java program to make it appear congruent and effectively fast to respond.

Threads

In light of the above discussion, a thread is the smallest unit of processing that can be scheduled by an operating system. Therefore, using threads, a programmer can effectively create two or more tasks[1] that run at the same time. The first call-to-action is to implement a set of tasks that a particular thread would execute. To do so, we require the creation of a Runnable process.

Creating a Runnable process block

A Runnable process block is a simple class that implements a run() method. Within the run() method is the actual task that needs to be executed by a running thread. By implementing a class with the Runnable interface, we ensure that the class holds a run() method. Consider the following program:

Computer code Code listing 1: A runnable process
import java.util.Random;
public class RunnableProcess implements Runnable {
    private String name;
    private int time;
    private Random rand = new Random();

    public RunnableProcess(String name) {
        this.name = name;
        this.time = rand.nextInt(999);
    }

    public void run() {
        try {
            System.out.printf("%s is sleeping for %d \n", this.name, this.time);
            Thread.sleep(this.time);
            System.out.printf("%s is done.\n", this.name);
        } catch(Exception ex) {
            ex.printStackTrace();
        }
    }
}

In the above code, we create a class called RunnableProcess and implement the Runnable interface to ensure that we have a run() method in the class declaration.

Example Code section 1.1: Implementing the Runnable interface
public class RunnableProcess implements Runnable {
    ...
    public void run() {
        ...
    }
}

We then declare the rest of the logic for the class. For the constructor, we take a String parameter that would serve as the name of the class. Then, we initialize the class member variable time with a random number between 0 and 999. To ensure the initialization of a random number, we use the Random class in the java.util package.

Example Code section 1.2: Including ability to generate random integers between 0 and 999
import java.util.Random;
...
private Random rand = new Random();
...
this.time = rand.nextInt(999);

The actual task that would be executed per this runnable block is presented within the run() method. To keep safe from exceptions occurring because of the concurrent programming, we wrap the code within this method with a try..catch block. The executing task actually consists of just three statements. The first outputs the provided name for the Runnable process, and the last reports that the thread has executed. Perhaps the most intriguing part of the code is the second statement: Thread.sleep(...).

Example Code section 1.3: The actual runnable process task
...
System.out.printf("%s is sleeping for %d \n", this.name, this.time);
Thread.sleep(this.time);
System.out.printf("%s is done \n", this.name);
...

This statement allows the thread executing the current runnable block to halt its execution for the given amount of time. This time is presented in milliseconds. But for our convenience, this time would be the random number generated in the constructor and can be anywhere between 0 and 999 milliseconds. We will explore this in a later section. Creating a Runnable process block is just the beginning. No code is actually executed. To do so, we would require the creation of threads that would then individually execute this task.

Creating threads

Once we have a Runnable process block, we can create various threads that can then execute the logic encased within such blocks. Multithreading capabilities in Java are utilized and manipulated using the Thread class. A Thread object therefore holds all the necessary logic and devices to create truly multithreaded programs. Consider the following program:

Computer code Code listing 2: Creating Thread objects
public class ThreadLogic {
    public static void main(String[] args) {
        Thread t1 = new Thread(new RunnableProcess("Thread-1"));
        Thread t2 = new Thread(new RunnableProcess("Thread-2"));
        Thread t3 = new Thread(new RunnableProcess("Thread-3"));
    }
}

Creating threads is as simple as the above program suggests. You just have to create an object of the Thread class and pass a reference to a Runnable process object. In the case above, we present the Thread constructor with the class object for the RunnableProcess class that we created in code listing 1. But for each object, we give a different name (i.e., "Thread-1" and "Thread-2", etc.) to differentiate between the three Thread objects. The above example only declares Thread objects and hasn't yet started them for execution.

Starting threads

Now, that we know how to effectively create a Runnable process block and a Thread object that executes it, we need to understand how to start the created Thread objects. This couldn't be simpler. For this process, we will be calling the start() method on the Thread objects and voilà, our threads will begin executing their individual process tasks.

Computer code Code listing 3: Starting the Thread objects
public class ThreadLogic {
    public static void main(String[] args) {
        Thread t1 = new Thread(new RunnableProcess("Thread-1"));
        Thread t2 = new Thread(new RunnableProcess("Thread-2"));
        Thread t3 = new Thread(new RunnableProcess("Thread-3"));

        t1.start();
        t2.start();
        t3.start();
    }
}

The above code will start all three declared threads. This way, all three threads will begin their execution one-by-one. However, this being concurrent programming and us having declared random times for the halting of the execution, the outputs for every one of us would differ. Following is the output we received when we executed the above program.

Computer code Output for code listing 3
Thread-1 is sleeping for 419
Thread-3 is sleeping for 876
Thread-2 is sleeping for 189
Thread-2 is done
Thread-1 is done
Thread-3 is done

It should be noted that the execution of the Thread didn't occur in the desired order. Instead of the order t1t2t3, the threads executed in the order of t1t3t2. The order in which the threads are executed is completely dependent on the operating system and may change for every execution of the program, thus making output of multithreaded application difficult to predict and control. Some people suggest that this is the major reason that adds to the complexity of multithreaded programming and its debugging. However, it should be observed that once the threads were put to sleep using the Thread.sleep(...) function, the execution intervals and order can be predicted quite capably. The thread with the least amount of sleeping time was t2 ("Thread-2") with 189 milliseconds of sleep hence it got called first. Then t1 was called and finally t3 was called.

Manipulating threads

It can be said that the execution order of the threads was manipulated to some degree using the Thread.sleep(...) method. The Thread class has such static methods that can arguably affect the execution order and manipulation of threads. Below are some useful static methods in the Thread class. These methods when called will only affect the currently running threads.

Method Description
Thread.currentThread() Returns the currently executing thread at any given time.
Thread.dumpStack() Prints a stack trace of the currently running thread.
Thread.sleep(long millis) Halts execution of the currently running thread for the given amount of time (in milliseconds).
throws InterruptedException
Thread.sleep(long millis, int nanos) Halts execution of the currently running thread for the given amount of time (in milliseconds plus provided nanoseconds).
throws InterruptedException
Thread.yield() Temporarily pauses the execution of the currently running thread to allow other threads to execute.

Synchronization

Given below is an example of creating and running multiple threads that behave in a synchronous manner such that when one thread is using a particular resource, the others wait until the resource has been released. We will talk more about this in later sections.

Computer code Code listing 4: Creation of the multiple Thread objects running synchronously
public class MultiThreadExample {
    public static boolean cthread;
    public static String stuff = " printing material";

    public static void main(String args[]) {
        Thread t1 = new Thread(new RunnableProcess());
        Thread t2 = new Thread(new RunnableProcess());
        t1.setName("Thread-1");
        t2.setName("Thread-2");
        t2.start();
        t1.start();
    }
    /*
     * Prints information about the current thread and the index it is
     * on within the RunnableProcess
     */
    public static void printFor(int index) {
        StringBuffer sb = new StringBuffer();
        sb.append(Thread.currentThread().getName()).append(stuff);
        sb.append(" for the ").append(index).append(" time.");
        System.out.print(sb.toString());
    }
}
class RunnableProcess implements Runnable {
    public void run() {
        for(int i = 0; i < 10; i++) {
            synchronized(MultiThreadExample.stuff) {
                MultiThreadExample.printFor(i);
                try {
               	    MultiThreadExample.stuff.notifyAll();
                    MultiThreadExample.stuff.wait();
                } catch(InterruptedException ex) {
                   ex.printStackTrace();
                }
            }
        }
    }
}
Computer code Output for code listing 4
Thread-1 printing material for the 0 time.
Thread-2 printing material for the 0 time.
Thread-1 printing material for the 1 time.
Thread-2 printing material for the 1 time.
Thread-1 printing material for the 2 time.
Thread-2 printing material for the 2 time.
Thread-1 printing material for the 3 time.
Thread-2 printing material for the 3 time.
Thread-1 printing material for the 4 time.
Thread-2 printing material for the 4 time.
Thread-1 printing material for the 5 time.
Thread-2 printing material for the 5 time.
Thread-1 printing material for the 6 time.
Thread-2 printing material for the 6 time.
Thread-1 printing material for the 7 time.
Thread-2 printing material for the 7 time.
Thread-1 printing material for the 8 time.
Thread-2 printing material for the 8 time.
Thread-1 printing material for the 9 time.
Thread-2 printing material for the 9 time.

Where are threads used?

Video games intensively use threads

Threads are used intensively in applications that require a considerable amount of CPU usage. For operations that are time-consuming and intensive, it is usually advised to use threads. A example of such an application would be a typical video game. At any given time, a video game involves various characters, objects in the surroundings and other such nuances that needs to be dealt with simultaneously. Dealing with each element or object within the game requires a fair amount of threads to monitor every object.

For example, take this screen-shot of a role-playing strategy game on the right. Here the game visuals depict various in-game characters moving about on the screen. Now imagine processing the movements, direction and behaviors of each of the characters visible on screen. It would certainly take a lot of time moving each character one-by-one if this were to be done one task after another. However if fundamentals of multi-threading are employed, each character would move in a synchronous manner with respect to others.

Threads are not only used heavily in video games, their use is common in everything from simple browser applications to complex operating systems and networking applications. Today it often goes beyond the simple preference of the developer but into the need to maximize the usefulness of contemporaneous hardware that is predicated in heavy multitasking.

References

  1. The number of tasks that can be run simultaneously for a single Java application depends on how many tasks an operating system allows to be multithreaded.

Daemon thread tutorial


Basic Synchronization

In a multi-threaded environment, when more than one thread can access and modify a resource, the outcome could be unpredictable. For example, let's have a counter variable that is incremented by more than one thread.

Beware! Synchronization is an ambiguous term. It doesn't consist of making all threads executing the same code section at the same time. It is the opposite. It prevents any two threads from executing the same code section at the same time. It synchronizes the end of one processing with the beginning of a second processing.

Example Code section 1.1: Counter implementation
int counter = 0;
...
counter += 1;

The above code is built up by the following sub-operations:

  • Read ; read variable counter
  • Add ; add 1 to the value
  • Save ; save the new value to variable counter

Let's say that two threads need to execute that code, and if the initial value of the counter variable is zero, we expect after the operations the value to be 2.

Thread 1   Thread 2
         
Read 0   Read 0
         
Add 1   Add 1
         
Save 1   Save 1
         

In the above case Thread 1 operation is lost, because Thread 2 overwrites its value. We'd like Thread 2 to wait until Thread 1 finishes the operation. See below:

Thread 1   Thread 2
         
Read 0   blocked
         
Add 1   blocked
         
Save 1   unblocked
         
  Read 1
     
  Add 1
     
  Save 2
     
Critical Section 
In the above example the code counter+=1 must be executed by one and only one thread at any given time. That is called critical section. During programming, in a multi-threading environment we have to identify all those pieces of code that belongs to a critical section, and make sure that only one thread can execute those codes at any given time. That is called synchronization.
Synchronizing threads 
The thread access to a critical section code must be synchronized among the threads, that is to make sure that only one thread can execute it at any given time.
Object monitor 
Each object has an Object monitor. Basically it is a semaphore, indicating if a critical section code is being executed by a thread or not. Before a critical section can be executed, the thread must obtain an Object monitor. Only one thread at a time can own that object's monitor.
A thread becomes the owner of the object's monitor in one of three ways 
  • By executing a synchronized instance method of that object. See synchronized keyword.
  • By executing the body of a synchronized statement that synchronizes on the object. See synchronized keyword.
  • For objects of type Class, by executing a synchronized static method of that class.
The Object Monitor takes care of the synchronization, so why do we need the "wait() and notify() methods"? 
For synchronization we don't really need them, however for certain situations it is nice to use them. A nice and considerate thread will use them. It can happen that during executing a critical section, the thread is stuck, cannot continue. It can be because it's waiting for an IO and other resources. In any case, the thread may need to wait a relatively long time. It would be selfish for the thread to hold on to the object monitor and blocking other threads to do their work. So the thread goes to a 'wait' state, by calling the wait() method on the object. It has to be the same object the thread obtained its object monitor from.
On the other hand though, a thread should call the wait() method only if there is at least one other thread out there who will call the notify() method when the resource is available, otherwise the thread will wait for ever, unless a time interval is specified as parameter.
Let's have an analogy. You go in a shop to buy some items. You line up at the counter, you obtain the attention of the sales-clerk - you get her "object-monitor". You ask for the item you want. One item needs to be brought in from a warehouse. It'll take more than five minutes, so you release the sales-clerk (give her back her "object-monitor") so she can serve other customers. You go into a wait state. Let's say there are five other customers already waiting. There is another sales-clerk, who brings in the items from the warehouse. As she does that, she gets the attention of the first sales-clerk, getting her object-monitor and notifies one or all waiting customer(s), so the waited customer(s) wake up and line up again to get the attention of the first sales-clerk.
Note the synchronization between the waiting customer and the sales-clerk who brings in the items. This is kind of producer-consumer synchronization.
Also note that there is only one object-monitor, belonging to the first sales-clerk. That object-monitor/the attention of clerk needs to be obtained first before a wait and a notify can happen.


final void wait() method 
The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread notifies the threads waiting on this object's monitor to wake up either through a call to the notify method or to the notifyAll method. The thread then waits until it can re-obtain ownership of the monitor and resume execution.
final void wait(long time) 
The same as wait, but the thread wakes after the specified duration of time passes, regardless of whether there was a notification or not.
final void notify() 
This method should only be called by a thread that is the owner of this object's monitor. Wakes up a single thread that is waiting on this object's monitor. If many threads are waiting on this object's monitor, one of them is chosen to be awakened. The choice is arbitrary and occurs at the discretion of the implementation. A thread waits on an object's monitor by calling one of the wait methods.
The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object. The awakened thread will compete in the usual manner with any other threads that might be actively competing to synchronize on this object; for example, the awakened thread enjoys no reliable privilege or disadvantage in being the next thread to lock this object.
final void notifyAll() 
Same as notify(), but it wakes up all threads that are waiting on this object's monitor.


What are the differences between the sleep() and wait() methods? 
Thread.sleep(millis)  
This is a static method of the Thread class. Causes the currently executing thread to sleep (temporarily cease execution) for the specified number of milliseconds. The thread does not lose ownership of any monitors. It means that if the thread has an object-monitor, all other threads that need that monitor are blocked. This method can be called regardless whether the thread has any monitor or not.
wait()  
This method is inherited from the Object class. The thread must have obtained the object-monitor of that object first before calling the wait() method. The object monitor is released by the wait() method, so it does not block other waiting threads wanting this object-monitor.



Client Server

In 1990s, the trend was moving away from Mainframe computing to Client/Server as the price of Unix servers dropped. The database access and some business logic were centralized on the back-end server, collecting data from the user program was installed on the front-end users' "client" computers. In the Java world there are three main ways the front-end and the back-end can communicate.

  • The client application uses JDBC (Java DataBase Connectivity API) to connect to the data base server, (Limited business logic on the back-end, unless using Stored procedures).
  • The client application uses RMI (Remote Method Invocation) to communicate with the back-end.
  • The client application uses a socket connection to communicate with the back-end.

Socket Connection Example

Figure 1:Simple Client Server Implementation

This page shows an example of a socket connection.

Create a Server

The Java language was developed having network computing in mind. For this reason it is very easy to create a server program. A server is a piece of code that runs all the time listening on a particular port on the computer for incoming requests. When a request arrives, it starts a new thread to service the request. See the following example:

Listening on a port

ComServer 
class is for listening on a port for a client.
Computer code Code listing 1.1: ComServer
import java.net.ServerSocket;
/**
 * -- Main Server Class; Listening on a port for client; If there is a client,
 * starts a new Thread and goes back to listening for further clients. --
 */
public class ComServer 
{
static boolean  GL_listening = true;
   /**
    * -- Main program to start the Server --
    */
   public static void main(String[] args) throws IOException
   {
      ComServer srv = new ComServer();
      srv.listen(); 
   } // --- End of Main Method ---

   /**
    * -- Server method; Listen for client --
    */
   public int listen() throws IOException
   {
    ServerSocket serverSocket = null;
    int iPortNumber = 9090;

       // --- Open the Server Socket where this should listen ---
       try {
           System.out.println( "*** Open the listening socket; at:"+ iPortNumber + " ***" );
           serverSocket = new ServerSocket( iPortNumber );
       } catch (IOException e) {
           System.err.println("Could not listen on port:"+iPortNumber );
           System.exit(1);
       }
       while ( GL_listening )
       {
        ComServerThread clientServ; 
           // --- Listening for client; If there is a client start a Thread -
           System.out.println( "*** Listen for a Client; at:"+ iPortNumber + " ***" );
           clientServ = new ComServerThread( serverSocket.accept() );
           // --- Service a Client ---
           System.out.println( "*** A Client came; Service it ***" );
           clientServ.start();   /* --- Use for multy Threaded --- */
      //     clientServ.run();    /* --- Use for Single Threaded --- */
       }

       // --- Close the Server socket;  Server exiting ---
       serverSocket.close();
    return 0;
   } // --- End of listen Method --- 
}  // --- End of ComServer Class ---
ServerSocket( iPortNumber ) 
Creates a server socket, bound to the specified port.
serverSocket.accept() 
Listens for a connection to be made to this socket and accepts it. The method blocks until a connection is made. It returns a new Socket.

Service One Client

ComServerThread 
This class extended from a Thread is responsible to service one client. The Socket connection will be open between the client and server. A simple protocol has to be defined between the client and server, the server has to understand what the client wants from the server. The client will send a terminate command, for which the server will terminate the socket connection. The ComServerThread class is responsible to handle all client requests, until the client sends a terminate command.
Computer code Code listing 1.2: ComServerThread
 /**
  * -- A class extended from a Thread; Responsible to service one client --
  */
 class '''ComServerThread''' extends Thread
 {
    private Socket clientSocket = null;
    COM_DATA tDataFromClient;
    COM_DATA tDataToClient; 
    ObjectInputStream oIn;
    ObjectOutputStream oOut;
    /**
     * -- Constructor --
     */
    public ComServerThread( Socket socket )
    {
       super( "ComServerThread" );
       this.clientSocket = socket;
    } // -- End of ComServerThread() constructor --
    /**
     * -- Overrun from the Thread (super) class --
     */
    public void run()
    {
       try {
          // --- Create the Writer; will be used to send data to client ---
          oOut = new ObjectOutputStream( clientSocket.getOutputStream() );
          // --- Create the Reader; will be used to get data from client ---
          oIn  = new ObjectInputStream( clientSocket.getInputStream() );
          // --- Create a new protocol object ---
          ComProtocol comp = new ComProtocol();
          // --- Send something to client to indicate that server is ready ---
          tDataToClient  = '''comp.processInput( null );'''
          '''sendDataToClient'''( tDataToClient, oOut );
          // --- Get the data from the client ---
          while ( true )
          {
             try {
                tDataFromClient = '''getDataFromClient( oIn )''';
                // --- Parse the request and get the reply ---
                tDataToClient = '''comp.processInput( tDataFromClient );'''
                // --- Send data to the Client ---
                '''sendDataToClient'''( tDataToClient, oOut );
             }
             catch ( EOFException e ) {
                System.out.println( "Client Disconnected, Bye, Bye" );
                break;
             }
             // --- See if the Client wanted to terminate the connection ---
             if ( tDataToClient.bExit )
             {
                System.out.println( "Client said Bye. Bye" );
                break;
             }
          }
          // --- Close resources;  This client is gone ---
          comp.Final();
          oOut.close();
          oIn.close();
          clientSocket.close();
       } catch ( IOException e ) {
        e.printStackTrace();
       }
    } // -- End of run() Method --
    /**
     * Get data from Client 
     */
    private static COM_DATA '''getDataFromClient'''( ObjectInputStream oIn ) throws IOException                                                                         
    {
        COM_DATA  tDataFromClient = null;         
        // --- Initialize variables ---
        //   tDataFromClient = new COM_DATA();
        while ( tDataFromClient == null )
        {
           try {
              // --- Read Line Number first --
              tDataFromClient = (COM_DATA) oIn.readObject();
           } catch ( ClassNotFoundException e ) {
               System.out.println( "ClassNotFound" );
           }
        }
        System.out.println( "Get: " + tDataFromClient.comData );
     return tDataFromClient;
    } // --- getDataFromClient() Method --- 
    /**
     * Send data to Client 
     */
    private static void '''sendDataToClient'''( COM_DATA tDataToClient,
                                           ObjectOutputStream  oOut ) throws IOException
    {         
        System.out.println( "Sent: " + tDataToClient.comData );
        oOut.writeObject( tDataToClient );
      return;
    } // -- End of sendDataToClient() Method --
 } // --- End of ComServerThread class ---
COM_DATA tDataFromClient 
This variable will contain the data object from the client.
COM_DATA tDataToClient 
This variable will contain the data object to be sent to the client.
sendDataToClient 
This method sends the data object to the client.
getDataFromClient 
This method gets the data object from the client.
processInput( tDataFromClient ) 
This method of the class ComProtocol interprets the client commands and returns the data object that will be sent back to the client.

Handling the request; implements the communication protocol

ComProtocol 
This class implements, and encapsulates the communication logic (protocol). The protocol is the following:
  1. The client initiate the connection.
  2. The server accepts it and sends an acknowledgment notifying that it's ready
  3. The client sends a request
  4. The server response based on the request
...
  1. The client sends a BYE request
  2. The server acknowledge the BYE request and disconnects the socket connection
  3. The client gets the acknowledgment to the BYE
...
  1. The client sends a SHUTDOWN request
  2. The server acknowledge the SHUTDOWN request and disconnects and also stops listening of other clients.
  3. The client gets the acknowledgment to the SHUTDOWN
Computer code Code listing 1.3: ComProtocol
 class '''ComProtocol'''
 {
  private static final int COM_STATUS_WAITING    = 0; 
  private static final int COM_STATUS_READY_SENT = 1;
  private static final int COM_STATUS_DATA_SENT  = 2;
  private static final int COM_STATUS_WAITING_FOR_TERMINALID = 3;
  private int state = COM_STATUS_WAITING;
  
  // --- Reference to 'BACK-END' module ---  
  private MqTeAccess mqTe;
  ...
    /**
     * Create a protokol object; CAll MQ INI function
     */
    public ComProtocol()
    {
     int    iRet = 0;
        // --- Initialize 'BACK-END' modules  ---
        mqTe. ...
 ...
    }
    /**
     * --- Process the Input and Create the output to the Client ---
     */
    public COM_DATA processInput( COM_DATA theInput )
    {
     COM_DATA theOutput;
        // --- Initialize Variables ---
        theOutput = new COM_DATA();
        // --- Check if the Clients want to disconnect ---
        if ( theInput != null ) 
        {
            if ( theInput.comData.equals('''"!BYE.@"''') )
            {
                // --- The Client wants to terminate; Echo data back to client
                theOutput.comData = "BYE.";
                // --- Mark the comunication to be terminated ---
                theOutput.bExit = true;
                // --- Set the internal state to wait for a new client ---
                state = COM_STATUS_WAITING;
                // --- Return Data object to be sent to the client ---
                return theOutput;
            }
            if ( theInput.comData.equals('''"!SHUTDOWN.@"''') )
            {
                // --- The Client wants to terminate; Echo data back to client
                theOutput.comData = "BYE.";
                // --- Mark the comunication to be terminated ---
                theOutput.bExit = true;
                // --- Tell the server to stop listening for new clients ---
                ComServer.GL_listening = false;
                // --- Set the internal state to wait for a new client ---
                state = COM_STATUS_WAITING;
                // --- Return Data object to be sent to the client ---
                return theOutput;
            }
        }
        if ( state == COM_STATUS_WAITING )
        {
            // --- Send ready Message to the Client ---
            theOutput.comData = "Ready:";
            // --- Set the internal state ready; and wait for TerminalId ---
            state = COM_STATUS_WAITING_FOR_TERMINALID;
        }
        else if ( state == COM_STATUS_WAITING_FOR_TERMINALID )
        {
         int iRet;
            // --- Get the Terminal ID ---
            sTermId = theInput.comData; 
            // --- Call 'BACK-END' modules ...  ---
            mqTe. ...
 ...
            // --- Send ready Message with the Server Version to the Client ---
            theOutput.comData = "Ready;Server Version 1.0:";
            // --- Set the internal state raedy; and wait for TerminalId ---
            state = COM_STATUS_READY_SENT;
        }
        else if ( state == COM_STATUS_READY_SENT )
        {
         int iRet;
            String sCommand = theInput.comData;
            // --- Call 'BACK-END' modules ...
 ...
            /*
            ** --- Check if we should get Response data ---
            */
            if ( theInput.iRet == COM_DATA.NOWAIT_FOR_RESPONSE ) {
                // -- Set the Output Value ---
                theOutput.iRet = iRet;
                theOutput.comData = "";
            }
            else {
                // --- Call 'BACK-END' modules ---
                mqTe. ...
                // --- Set the Output Value ---
                theOutput.comData    = mqTe.sResponseBuffer; 
                theOutput.iRet       = iRet;
            }
        }
     return theOutput;
    }  // --- End of Method processInput() ---
 } // --- End of ComProtocol Class Definition ---

----

The Data object that goes through the network

COM_DATA 
is data structure class that is transmitted through the network. The class contains only data.
Computer code Code listing 1.4: COM_DATA
 /**
  * COM_DATA data structure 
  */
 public class COM_DATA implements Serializable
 {
  public String  comData;
  public boolean bExit;
  public int     iRet;
    /**
     * --- Constants values can be passed in in iRet to the Server ---
     */
    static final int WAIT_FOR_RESPONSE    = 0;
    static final int NOWAIT_FOR_RESPONSE  = 1;
   /**
    * Initialize the data structure
    */
   public COM_DATA()
   {
      comData     = "";
      bExit       = false;
      iRet        = 0;
   } // -- End of COM_DATA() Constructor --   
   /**
    * Copy over it contents 
    */
   public void copy( COM_DATA tSrc )
   {
      this.comData     = tSrc.comData;
      this.bExit       = tSrc.bExit;
      this.iRet        = tSrc.iRet;
    return;
   } 
 } // -- End of COM_DATA class --

Create the Client

A client code for a server/service is usually an API that a user application uses to interface to the server. With the help of a client API the user application does not have to know how to connect to the server to get services.

ComClient 
This class is the client API. The application is using this class to communicate with the server.

The following is the client class for the above server:

Computer code Code listing 1.5: ComClient
 public class ComClient
 {
  private Socket         comSocket;
  private ObjectOutputStream oOut;
  private ObjectInputStream  oIn;
  private boolean         IsItOpen = false;       
    /**
     * --- Open Socket ---
     */
    public void openCom( String sServerName,
                         int    iPortNumber ) throws UnknownHostException,
                                                              IOException  
    {
       try {
          // --- Open Socket for communication ---
          comSocket = new Socket( sServerName, iPortNumber );     
          // --- Get Stream to write request to the Server ---
          oOut = new ObjectOutputStream( comSocket.getOutputStream() );     
          // --- Get Stream// to read from the Server
          oIn = new ObjectInputStream( comSocket.getInputStream());
          // --- Set internal Member variable that the Communication opened ---
          IsItOpen = true;
       } catch ( java.net.UnknownHostException e ) {
          System.err.println( "(openCom:)Don't know about host: "+sServerName );
          IsItOpen = false;
          throw( e );                                         
       } catch ( java.io.IOException e ) {
          System.err.println("(openCom:)Couldn't get I/O for the connection to: "+ sServerName );
          IsItOpen = false;
          throw( e );         
       }               
    }
    /**
     * --- Check if Socket is open ---
     */
    public boolean isItOpen()
    {
      return IsItOpen;
    }     
    /**
     * --- Get data string from the Server ---
     */
    public void getServerData( COM_DATA tServData ) throws IOException
    {
        // --- Initialize Variables ---
        tServData.comData = "";
        // --- Get the Response from the Server ---              
        try {
           tServData.copy( (COM_DATA) oIn.readObject() );
        }   
        catch ( ClassNotFoundException e ) {
            System.out.println( "Class Not Found" );
        } 
        System.out.println( "Server: " + tServData.comData );
        if ( tServData.comData.equals("BYE.") )
        {
            tServData.bExit = true;
        }        
     return;
    }
    /**
     * --- Send data to the Server ---
     */
    public void sendDataToServer( COM_DATA tServData ) throws IOException
    {
        // --- Send the data string ---
        System.out.println( "Send: " + tServData.comData );
        oOut.writeObject( tServData );
     return;
    } 
    /**
     * --- Close Socket --- 
     */
    public void closeCom() throws IOException
    {
        oOut.close();
        oIn.close();
        comSocket.close();
        IsItOpen = false;
    }    
 }
getServerData( COM_DATA tServData ) 
This method reads the data from the server and copies the values to tServData object.
sendDataToServer( COM_DATA tServData ) 
This method sends the tServData object through the network to the server.
oIn.readObject() 
This method returns the data object sent by the server.
oOut.writeObject( tServData ) 
This method sends the data object to the server.



Remote Method Invocation

Java's Remote Method Invocation (commonly referred to as RMI) is used for client and server models. RMI is the object oriented equivalent to RPC (Remote procedure call).

The Java Remote Method Invocation (RMI) system allows an object running in one Java Virtual Machine (VM) to invoke methods of an object running in another Java VM. RMI provides for remote communication between programs written in the Java programming language.

RMI is only defined for use with the Java platform. If you need to call methods between different language environments, use CORBA. With CORBA a Java client can call a C++ server and/or a C++ client can call a Java server. With RMI that can not be done.

STUB and SKELETON

The remote method invocation goes through a STUB on the client side and a so called SKELETON on the server side.

CLIENT --> STUB --> ... Network ... --> SKELETON --> REMOTE OBJECT

Prior to Java 1.2 the skeleton had to be explicitly generated with the rmic tool. Since 1.2 a dynamic skeleton is used, which employs the features of Java Reflection to do its work.

rmiregistry

Remote objects can be listed in the RMI Registry. Clients can get a reference to the remote object by querying the Registry. After that, the client can call methods on the remote objects. (Remote object references can also be acquired by calling other remote methods. The Registry is really a 'bootstrap' that solves the problem of where to get the initial remote reference from.)

The RMI Registry can either be started within the server JVM, via the LocateRegistry.createRegistry() API, or a separate process called rmiregistry that has to be started before remote objects can be added to it, e.g. by the command line in Unix:

Standard input or output rmiregistry on Unix
rmiregistry <port> &

or under Windows:

Standard input or output rmiregistry on Windows
start rmiregistry <port>

If port is not specified the default 1099 is used. The client will need to connect to this port to access the Registry.

The Registry can also be started from a program by calling the following code:

Example Code section 1: rmiregistry starting
import java.rmi.registry.LocateRegistry;
...
Registry reg = LocateRegistry.createRegistry(iPort);

Objects passed in as parameters to the remote objects's methods will be passed by value. If the remote object changes the passed-in object values, it won't be reflected on the client side, this is opposite what happens when a local object is called. Objects that used as parameters for remote methods invocation must implement the java.io.Serializable interface, as they are going to be serialized when passed through the network, and a new object will be created on the other side.

However, exported remote objects passed as parameters are passed by remote reference.

rmic tool

RMI Remote object

The remote object has to either extend the java.rmi.server.UnicastRemoteObject object, or be explicitly exported by calling the java.rmi.server.UnicastRemoteObject.exportObject() method.

RMI clients

Here is an example of RMI client:

Computer code Code listing 7.10: HelloClient.java
 1 import java.rmi.registry.LocateRegistry;
 2 import java.rmi.registry.Registry;
 3 
 4 public class HelloClient{
 5 
 6     private HelloClient() {}
 7 
 8     public static void main(String[] args) {
 9         String host = (args.length < 1) ? null : args[0];
10         try {
11             Registry registry = LocateRegistry.getRegistry(host);
12             Hello stub = (Hello) registry.lookup("Hello");
13             String response = stub.sayHello();
14             System.out.println("response: " + response);
15         } catch (Exception e) {
16             System.err.println("Client exception: " + e.toString());
17             e.printStackTrace();
18         }
19     }
20 }



EJB

Enterprise JavaBeans (EJB) technology is the server-side component architecture for Java Platform, Enterprise Edition (Java EE). EJB technology enables to create distributed, transactional, secure and portable application component objects.

EJB supports the development and deployment of component based business applications. Applications written using the Enterprise JavaBeans architecture are scalable, transactional, and multi-user secure. These applications may be written once, and then deployed on any server platform that supports the Enterprise JavaBeans specification.

EJB History

EJB Features

  • Security Management
  • Persistence Management
  • Transaction Management
  • Distributable Interoperable Management
  • Exception Management

Types of EJB

  • Session Beans
    • StateFull Session Beans
    • Stateless Session Beans
  • Entity Beans
  • Message Driven Beans

Problems with EJB as a component based development

EJBs are an attempt to create component based application development. With EJBs it is easier to develop components, but the same basic and fundamental maintenance problem will still be there. That is the dependencies between the client and the components. The usage of a component is fixed, changes on the component interface cause to break the client code. The same client/server problem comes back, that is as the users of a component increases the maintenance of that component getting harder and harder until it goes to impossible.

For a true component based application development we need to standardize the usage of a component. The client must somehow flexibly figure out automatically how to use a component, so component changes don't affect any of the clients using that component. Without that flexibility, a true component based application development will remain as an idea, a dream, a theory without significant practical use. If we had that flexibility, it could cause a paradigm shift in the software development industry.

JINI was an attempt from Sun to address this flexibility problem. In JINI, the client download the component interface implementation and execute it in the client space.

So we need to mix (somehow) EJB and JINI technologies to come up with a true flexible component based technology.

References

See also

External links



Jini

After J2EE, Sun had a vision about the next step of network computing: in a network environment, there would be many independent services and consumers. That is JavaSpaces. JavaSpaces would allow these services/consumers to interact dynamically with each other in a robust way. It can be viewed as an object repository that provides a distributed persistent object exchange mechanism (persistent can be in memory or disk) for Java objects. It can be used to store the system state and implement distributed algorithms. In a JavaSpace, all communication partners (peers) communicate by sharing state. It is an implementation of the Tuple spaces idea.

JavaSpaces is used when someone wants to achieve scalability and availability and at the same time reducing the complexity of the overall system.

Processes perform simple operations to write new objects into a JavaSpace, take objects from a JavaSpace, or read (make a copy of) objects from the JavaSpace.

In conventional applications, objects are assembled from the database before presenting to the end user. In JavaSpace applications, we keep the ready made "end user" objects and store them in the JavaSpace. In JavaSpace applications the services are decoupled from each other; they communicate through objects that they write and read/take from the JavaSpace. Services search for objects that they want to take or read from the Space by using template object.

JINI

JavaSpaces technology is part of the Java Jini technology. The basic features of JINI are:

  • No user intervention is needed when services are brought on or offline. (In contrast to EJBs where the client program has to know the server and port number where the EJB is deployed. In JINI the client is supposed to find, discover the service in the network.)
  • Self healing by adapting when services (consumers of services) come and go. Services need to periodically renew a lease to indicate that they are still available.
  • Consumers of JINI services do not need prior knowledge of the service's implementation. The implementation is downloaded dynamically and run on the consumer JVM, without configuration and user intervention. For example, the end user may be presented with slightly different user interface depending which service is being used at the time. The implementation of those user interface code would be provided by the service being used.
This fact that the implementation is running on the consumer/client's JVM can increase performance, by eliminating the need of remote calls.

A minimal JINI network environment consists of:

  • One or more services
  • A lookup-service keeping a list of registered services
  • One or more consumers

The JINI Lookup Service

The lookup service is described in the : Jini Lookup Service Specification (reggie). This service interface defines all operations that are possible on the lookup service. Clients locate services by requesting with a lookup server that implements a particular interface. Client asks the lookup server for all services that implement the particular service interface. The lookup service returns service objects for all registered services that implement the given interface. The client may invoke methods on that object in order to interact directly with the server.

Lookup Discovery

Jini Discovery and Join Specification describes how does the client find the jini lookup service. There is a protocol to do that, jini comes with a set of API's that implement that protocol. The Jini Discovery Utility Specification defines a set of utility classes that are used to work with the protocol.

Leasing

When a service registers with the lookup service, it receives a lease from the lookup service, described in the Jini Distributed Leasing Specification.

Entries and Templates

Distributed Events

Annotations

Javadoc is the Java source code document generator and was introduced with the Java language from version 1.0 . Well commented Java code is supposed to have Javadoc tags. Those tags are in the /** ... */ comment blocks, so the compiler ignores them. A separate utility would read the code and create the Java API html files.

The Javadoc API documentations are well known. The Java JDK classes are coming with Javadoc API documentations. Most popular IDE tools automatically read Javadoc tags and wherever that class, attribute or method are used, the tags content are displayed automatically, when the mouse cursor is over the text.

As Java matured, the "Javadoc concept" was recognized as an excellent tool for other purposes, like generating XML descriptors, or even generating Java code, with the help of the XDoclet open source program.

With the help of the XDoclet program, it was possible to use additional Javadoc tags in the code that this program would understand and generate code or data. For example, Javadoc tags were introduced to generate XML descriptors for EJBs. It introduced an additional step in the build process of an EJB, and compiling the code XDoclet would generate the XML descriptors.

Recognizing its usefulness, in Java 5, annotation was added to the Java language. Annotation tags are NOT inside a comment block. An annotation is part of the class and it may be accessed at runtime.

Wherever XML descriptors were heavily used, now an alternative way is available that is the Java annotation. From EJB 3.0, it is possible to define EJBs without using XML. Also the new JPA (Java Persistent API) uses annotations.

It is important to note, that Javadoc and annotation are two different constructs.

  • Javadoc tags are inside a comment block and as such ignored by the compiler.
  • Annotation tags are outside of comment blocks and they are type checked by the compiler.



Javadoc

Java allows users to document the classes and the members by using a particular syntax of comment.

Syntax

A documentation comment is framed by slash-star-star and star-slash (i.e. /** ... */). The documentation is in the HTML format.

Computer code Code listing 8.1: Example.java
1 /**
2  *  A class to give an <b>example</b> of HTML documentation.
3  */
4 public class Example {
5     /** ...Documentation of a member with the type integer named example... */
6     public int example;
7 }

A documentation comment is placed just above the commented entity (class, constructor, method, field).

In a documentation comment, the first part is a description text in the HTML format. The second part is a list of special attributes whose name starts with an at sign (@):

Example Code section 8.1: Documentation comment.
1 /**
2  *  Get the sum of two integers.
3  *  @param a The first integer number.
4  *  @param b The second integer number.
5  *  @return The value of the sum of the two given integers.
6  */
7 public int sum(int a, int b) {
8     return a + b;
9 }
Get the sum of two integers.
Description of the sum method.
@param a The first integer number.
Description attribute of the parameter a of the method.
@param b The second integer number.
Description attribute of the parameter b of the method.
@return The value of the sum of the two given integers.
Description attribute of the value returned by the method.

Here is a non exhaustive list of special attributes:

Attribute and syntax In a comment of ... Description
@author author class Name of the author of the class.
@version version class Version of the class.
@deprecated description class, constructor, method, field Flags the entity as deprecated (old version), describes why and by what replace it.

If the entity flagged as deprecated by this attribute is used, the compiler give a warning.

@see reference class, constructor, method, field Add a link in the section "See also".
@param id description constructor and method Describes the method parameter.
@return description method Describes the value returned by the method.
@exception type description constructor and method Describes the reason of the throw of an exception of the specified type (throws clause).

See also annotations since Java 5.

Documentation

The JDK provides a tool named javadoc which allows to generate the documentation of the well commented classes. The javadoc command without argument give the complete syntax of the command.

Example : for a class named Example defined in a package named org.wikibooks.en dans le fichier C:\ProgJava\org\wikibooks\en\Example.java :

Computer code Code listing 8.2: Example.java
 1 package org.wikibooks.en;
 2 
 3 /**
 4  *  An example class.
 5  */
 6 public class Example {
 7     /**
 8     Get the sum of two integers.
 9     @param a The first integer number.
10     @param b The second integer number.
11     @return The value of the sum of the two given integers.
12     */
13     public int sum(int a, int b) {
14         return a + b;
15     }
16 }

The documentation can be generated in a specific folder (C:\ProgDoc for example) with the following command:

Standard input or output Command 8.1: Documentation generation
$ javadoc -locale en_US -use -classpath C:\ProgJava -sourcepath C:\ProgJava -d C:\ProgDoc org.wikibooks.en

The options of this command are described below:

-locale en_US
The documentation in US English.
-use
Create the pages about the use of the classes and the packages.
-classpath C:\ProgJava
The path of the compiled classes (*.class).
-sourcepath C:\ProgJava
The path of the source classes (*.java).
-d C:\ProgDoc
The path where the documentation must be generated.
org.wikibooks.en
The name of the package to document. It is possible to specify several packages, or one or several class names to document only those ones.

The description page of a package copy the description text from the file named package.html which should be placed in the given folder. In our example, we should document the package in the file C:\ProgJava\org\wikibooks\en\package.html.

Since Java 5[1], the package.html file can be replaced by a special Java file named package-info.java containing only the package declaration preceding by a documentation comment.

Computer code Code listing 8.3: C:\ProgJava\org\wikibooks\en\package-info.java
1 /**
2  * This fake package is used to illustrate the Java wikibook.
3  * at <i>en.wikibooks.org</i>.
4  */
5 package org.wikibooks.en;

References

  1. http://docs.oracle.com/javase/6/docs/technotes/tools/windows/javadoc.html#packagecomment



Annotations/Introduction

Introduction

In Java, an annotation is a language construct (introduced in J2SE 1.5) that provides a mechanism for including metadata directly in the source code.

Annotations can provide metadata for Java classes, attributes, and methods. Syntactically, annotations can be viewed as a special kind of modifier and can be used anywhere that other modifiers (such as public, static, or final) can be used.

One of the main forces of adding this feature to Java was the wide spread use of XML descriptors to add additional information, metadata, for Java classes. Frameworks like EJB, JSF, Spring, Hibernate were heavily using external XML descriptors. The problem of those external descriptors was that those files are out of reach of the Java compiler and for that reason compiler type checking could not be used. A small spelling mistake bug in a huge XML descriptor file is hard to locate and fix. On the other hand the Java annotations use the Java compiler type checking features so spelling mistakes in annotation names will be caught by the Java compiler.

In summary, annotations can be...

  • used as a source of information for the compiler;
  • made available for compile-time or deployment-time processing;
  • examined at runtime.

External links

  • [1] The Java™ Tutorial on Annotations



Annotations/Custom Annotations

Annotations can be viewed as a source of defining meta-data for a piece of code in Java. The annotation @CodeDescription used in the following sections does not come as a part of the Java API.

Annotation Type Declaration

Before you can use an annotation with classes, theirs members and statements or expressions, you need to define an annotation type. Following is the syntax on how to define a type for the mentioned annotation.

Computer code Code listing 1.1: Annotation type declaration
@interface CodeDescription
{
    String author();
    String version();
}

That's it! Our first ever annotation has been defined. Now, we can use it with any of our classes. An annotation definition if you look closely resembles the definition of a normal interface, except that the interface keyword is preceded by the @ character. Some refer to this syntactical declaration as the annotation type declaration due to the fact that @ is 'AT' or 'Annotation Type' for that very instance.

Annotation Element Declarations

What look like methods in the body of the annotation definition are called annotation element declarations. These are the named entities that we used with the annotation body in the example in the previous section. However, for the sake of clarity, code below also represents the calling of the following annotation:

Computer code Code listing 1.2: Calling of annotation
public class MyMethod
{
    @CodeDescription
    (
        author = "Unknown",
        version = "1.0.0.1"
    )
    public void doSomething()
    {
        ...
    }
}

Note:
Instead of using the declaration with the class, the annotation is used with the method doSomething(). This might not demonstrate the power of annotations yet, but more will be explored in later chapters.

Using a default value

Now, for instance, you want the annotation to know that if no value for the version element is present, then it should use a default value. Declaring a default value would be done the following way.

Computer code Code listing 1.3: Using default values.
@interface CodeDescription
{
    String author();
    String version() default "1.0.0.1";
}

So, now if you use the same code again, you can ignore the version element because you know that the value is to be provided by default.

Computer code Code listing 1.4: Pre-defined value.
public class MyMethod
{
    @CodeDescription(author = "Sysop")
    public void doSomething()
    {
        ...
    }
}



Annotations/Meta-Annotations

There are five annotation types in the java.lang.annotation package called meta-annotations. These annotation types are used to annotate other annotation types.

Documented

If a member is annotated with a type itself marked as @Documented, then that member will be documented as annotating that type.

Computer code Code listing 1.1: Use of @Documented
@interface Secret { }

@Documented
@interface NotSecret { }

@Secret
@NotSecret
public class Example {
}

In the documentation for the Example class, such as the JavaDoc, Example will be shown as annotated with @NotSecret, but not @Secret.

Clipboard

To do:
Add the render of a Javadoc.

Inherited

Exactly as the name sounds, an @Inherited annotation type is inherited by subclasses of an annotated type.

Computer code Code listing 1.2: Use of @Inherited
@Inherited
@interface ForEveryone { }

@interface JustForMe { }

@ForEveryone
@JustForMe
class Superclass { }

class Subclass extends Superclass { }

In this example, Superclass has been explicitly annotated with both @ForEveryone and @JustForMe. Subclass hasn't been explicitly marked with either one; however, it inherits @ForEveryone because the latter is annotated with @Inherited. @JustForMe isn't annotated, so it isn't inherited by Subclass.

Repeatable

A @Repeatable annotation type is repeatable - i.e. can be specified multiple times on the same class. This meta-annotation was added in Java 8.

Retention

Different annotation types have different purposes. Some are intended for use with the compiler; others are meant to be reflected dynamically at runtime. There's no reason for a compiler annotation to be available at runtime, so the @Retention meta-annotation specifies how long an annotation type should be retained. The value attribute is one of the java.lang.annotation.RetentionPolicy enum constants. The possible values, in order from shortest to longest retention, are as follows:

RetentionPolicy.SOURCE
The annotation will not be included in the class file. This is useful for annotations which are intended for the compiler only.
RetentionPolicy.CLASS
The annotation will be included in the class file, but cannot be read reflectively.
RetentionPolicy.RUNTIME
The annotation can be reflected at runtime.

If no @Retention policy is specified, it defaults to RetentionPolicy.CLASS.

Target

The @Target meta-annotation determines what may be marked by the annotation. The value attribute is one or more of the java.lang.annotation.ElementType enum constants. Those constants are ElementType.ANNOTATION_TYPE, CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, and TYPE.

If @Target is not specified, the annotation may be used on any program element.



Annotations/Compiler and Annotations

Annotations can be used by the compiler to carry out certain directives. Much that you'd love programming in Java, you probably would have been fussed about compiler warnings. Compiler warnings are not necessarily errors but are warnings that tell you the code might malfunction because of some reason.

Taming the compiler

You can issue directive to the compiler in the shape of three pre-defined annotation to tell it what sort of pre-processing a certain bit of code requires. The three annotations are:

  • @Deprecated
  • @Override
  • @SuppressWarnings(..)

@Deprecated is used to flag that a method or class should no longer be used, normally because a better alternative exists. Compilers and IDEs typically raise a warning if deprecated code is invoked from non deprecated code. [2]

@Override flags that a method overrides a method in a superclass. If there is no overridden method, a compile error should occur. [3]

@SuppressWarnings(..) SuppressWarnings tells the compiler not to report on some, or all, types of warnings. It can be applied to a type, a method or a variable. [4]

External links

  • [5] Advanced usage of the @SuppressWarnings(..) annotation



Designing user interfaces

Basic IO

This section covers the Java platform classes used for basic input and output. But before we begin we need to have a concrete understanding of what input and output means in programming. To grasp this concept, think of the Java platform as a system.

Understanding input and output

The Java platform is an isolated entity, a space on your OS in a way, where everything outside this system is its environment. The interaction between the system and its environment is a two-way dialog of sorts. Either the system receives messages from its environment, or it conveys its messages to the same. When a message is received by the system, it is called an input, its opposite is an output. On a whole, this communication is termed input/output abbreviated as I/O.

The following chapters are designed to introduce basic input and output in Java, including reading text input from the keyboard, outputting text to the monitor, and reading/writing files from the file system. More advanced user interaction using Graphics and Graphical User Interface (GUI) programs is taken up in the later section on Swing.

There are two packages for I/O: the older java.io package (does not support symbolic links) and the newer java.nio ("new io") package that has improved exception handling at java.nio.file.

Simple Java Output: Writing to the Screen

Writing to the screen is very easy, and can be accomplished using one of two methods:

Example Code section 9.1: Print "Hello world" without advancing to a new line
System.out.print("Hello world");
Standard input or output Output on the screen
Hello world

Example Code section 9.2: Print "Hello world" and advance to a new line
System.out.println("Hello world");
Standard input or output Output on the screen
Hello world


Simple Java Input: Inputting from the keyboard

As of version 5, Java provides a class in the java.util package called Scanner that simplifies keyboard input.

Example Code section 9.3: Inputting with Scanner
Scanner kbdIn = new Scanner(System.in); // Instantiating a new Scanner object
System.out.print("Enter your name: "); // Printing out the prompt
String name = kbdIn.nextLine(); // Reading a line of input (until the user hits enter) from the keyboard
// and putting it in a String variable called name
System.out.println("Welcome, " + name); // Printing out welcome, followed by the user's name
Standard input or output On the screen
Enter your name: John Doe
Welcome, John Doe

Alternatively, one could write a method to handle keyboard input:

Example Code section 9.4: Line reader
public String readLine() {
  // Creates a new BufferedReader object
  BufferedReader x = new BufferedReader(new InputStreamReader(System.in));

  // Reads a line of input and returns it directly
  return x.readLine();
}

Note that the code above shouldn't be used in most applications, as it creates new Objects every time the method is run. A better alternative would be to create a separate class file to handle keyboard input.



Streams

The most basic input and output in Java (System.in and System.out fields that have been used in the Basic I/O) is done using streams. Streams are objects that represent sources and destinations of data. Streams that are sources of data can be read from, and streams that are destinations of data can be written to. A stream in Java is an ordered sequence of bytes of undetermined length. Streams are ordered and in sequence so that the java virtual machine can understand and work upon the stream. Streams are analogous to water streams. They exist as a communication medium, just like electromagnetic waves in communication. The order or sequence of bytes in a Java stream allow the virtual machine to classify it among other streams.

Java has various inbuilt streams implemented as classes in the package java.io like the classes of System.in and System.out. Streams can be classed as both input and output streams. All Java streams are derived from Input Stream (java.io.InputStream) and Output Stream (java.io.OutputStream) classes. They are abstract base classes meant for other stream classes. The System.in is the input stream class derivative and analogically System.out is the output counterpart. Both are basic classes used to directly interact with input and output through console, similarly follows System.err. Also Java has streams to communicate across different parts of a program or even among threads. There are also classes that "filter" streams, changing one format to another (e.g. class DataOutputStream, which translates various primitive types to byte streams).

It is a characteristic of streams that they deal only in one discrete unit of data at a time, and different streams deal with different types of data. If one had a stream that represented a destination for bytes, for example, one would send data to the destination one byte at a time. If a stream was a source of byte data, one would read the data a byte at a time. Because this is the only way to access data from a stream, in this latter case, we wouldn't know when we had read all the data from the stream until we actually got there. When reading a stream, one generally has to check each unit of data each read operation to see if the end of the stream has been reached (with byte streams, the special value is the integer -1, or FFFF hex).

Input streams

Input streams acquire bytes for our programmed java application/program (e.g. a file, an array, a keyboard or monitor, etc.). InputStream is an abstract class that represents a source of byte data. It has a read() method, which returns the next byte in the stream and a close() method, which should be called by a program when that program is done with the stream. The read() method is overloaded, and can take a byte array to read to. It has a skip() method that can skip a number of bytes, and an available() method that a program can use to determine the number of bytes immediately available to be read, as not all the data is necessarily ready immediately. As an abstract class, it cannot be instantiated, but describes the general behavior of an input stream. A few examples of concrete subclasses would be ByteArrayInputStream, which reads from a byte array, and FileInputStream, which reads byte data from a file.

In the following example, we print "Hello world!" on the screen several times. The number of times the message is printed is stored in a file named source.txt. This file should only contain a integer and should be placed in the same folder of the ConfiguredApplication class.

Computer code Code listing 9.1: Example of input stream.
 1 import java.io.File;
 2 import java.io.FileInputStream;
 3  
 4 public class ConfiguredApplication {
 5  
 6   public static void main(String[] args) throws Exception {
 7  
 8     // Data reading
 9     File file = new File("source.txt");
10     FileInputStream stream = new FileInputStream(file);
11  
12     StringBuffer buffer = new StringBuffer();
13  
14     int character = 0;
15     while ((character = stream.read()) != -1) {
16       buffer.append((char) character);
17     }
18  
19     stream.close();
20  
21     // Data use
22     Integer readInteger = Integer.parseInt(buffer.toString());
23     for (int i = 0; i < readInteger ; i++) {
24       System.out.println("Hello world!");
25     }
26   }
27 }

The close() method is not always mandatory but can avoid some inter-process concurrency conflicts. However if it occurs before a read() or write() (in the same process) they return the warning Stream closed.

The class start to identify the filename with a File object. The File object is used by an input stream as the source of the stream. We create a buffer and a character to prepare the data loading. The buffer will contain all the file content and the character will temporary contain each character present in the file, one after one. This is done while{}in the loop. Each iteration of the loop will copy a character from the stream to the buffer. The loop ends when no more character is present in the stream. Then we close the stream. The last part of the code use the data we have loaded in from the file. It is transformed into string and then into an integer (so the data must be an integer). If it works, the integer is used to determine the number of time we print "Hello world!" on the screen. No try/catch block has been defined for readability but the thrown exceptions should be caught.

Let's try with the following source file:

Computer code Code listing 9.2: source.txt

4

We should obtain this:

Standard input or output Output for ConfiguredApplication
$ java ConfiguredApplication
Hello world!
Hello world!
Hello world!
Hello world!
Warning If it shows a FileNotFoundException or an IOException, the source may not be placed in the right folder or its name is badly spelled.
If it shows a NumberFormatException, the content of the file may not be an integer.

There is also Reader which is an abstract class that represents a source of character data. It is analogous to InputStream, except that it deals with characters instead of bytes (remember that Java uses Unicode, so that a character is 2 bytes, not one). Its methods are generally similar to those of InputStream. Concrete subclasses include classes like FileReader, which reads characters from files, and StringReader, which reads characters from strings. You can also convert an InputStream object to a Reader object with the InputStreamReader class, which can be "wrapped around" an InputStream object (by passing it as an argument in its constructor). It uses a character encoding scheme (which can be changed by the programmer) to translate a byte into a 16-bit Unicode character.

Output streams

Output Streams direct streams of bytes outwards to the environment from our program or application. OutputStream is an abstract class which is the destination counterpart of InputStream. OutputStream has a write() method which can be used to write a byte to the stream. The method is overloaded, and can take an array as well. A close() method closes the stream when the application is finished with it, and it has a flush() method. The stream may wait until it has a certain amount before it writes it all at once for efficiency. If the stream object is buffering any data before writing it, the flush() method will force it to write all of this data. Like InputStream, this class cannot be instantiated, but has concrete subclasses that parallel those of InputStream, eg ByteArrayOutputStream, FileOutputStream, etc.

In the following example, we store the current time in an already existing file called log.txt located in the same folder than the class.

Computer code Code listing 9.2: Example of output stream.
 1 import java.io.File;
 2 import java.io.FileOutputStream;
 3 import java.util.Date;
 4  
 5 public class LogTime {
 6     public static void main(String[] args) throws Exception {
 7         // Generate data
 8         String timeInString = new Date().toString();
 9 
10         // Store data
11         File file = new File("log.txt");
12         FileOutputStream stream = new FileOutputStream(file);
13 
14         byte[] timeInBytes = timeInString.getBytes();
15 
16         stream.write(timeInBytes);
17         stream.flush();
18         stream.close();
19     }
20 }

This case is more simple as we can put all the data in the stream at the same time. The first part of the code generate a string containing the current time. Then we create a File object identifying the output file and an output stream for this file. We write the data in the stream, flush it and close it. That's all. No try/catch block has been defined for readability but the thrown exceptions should be caught.

Warning In order to read a text file several times from the beginning, a FileChannel variable should be introduced, only to reposition the reader.

Now let's execute it:

Standard input or output LogTime execution
$ java LogTime

We should obtain this content:

Computer code Code listing 9.4: log.txt

Tue Dec 5 19:33:04 CEUTC 2017

Warning If it shows a FileNotFoundException or an IOException, the file should not have been created or it is not placed in the right folder.

There is also Writer which is a character counterpart of OutputStream, and a destination counterpart to Reader, this is also an abstract superclass. Particular implementations parallel those of Reader, eg FileWriter, StringWriter, and OutputStreamWriter, for converting a regular OutputStream into a reader so that it can take character data.

System.out and System.err

System is a class in the package java.lang with a number of static members that are available to Java programs. Two members that are useful for console output are System.out and System.err. Both System.out and System.err are PrintStream objects. PrintStream is a subclass of FilterOutputStream, itself a subclass of OutputStream (discussed above), and its main purpose is to translate a wide variety of data types into streams of bytes that represent that data in characters according to some encoding scheme.

System.out and System.err both display text to a console where the user can read it, however what this means exactly depends on the platform used and the environment in which the program is running. In BlueJay and Eclipse IDE, for example, there is a special "terminal" window that will display this output. If the program is launched in Windows, the output will be sent to the DOS prompt (usually this means that you have to launch the program from the command line to see the output).

System.out and System.err differ in what they're supposed to be used for. System.out should be used for normal program output, System.err should be used to inform the user that some kind of error has occurred in the program. In some situations, this may be important. In DOS, for instance, a user can redirect standard output to some other destination (a file, for example), but error output will not be redirected, but rather displayed on the screen. If this weren't the case, the user might never be able to tell that an error had occurred.


New I/O

Versions of Java prior to J2SE 1.4 only supported stream-based blocking I/O. This required a thread per stream being handled, as no other processing could take place while the active thread blocked waiting for input or output. This was a major scalability and performance issue for anyone needing to implement any Java network service. Since the introduction of NIO (New I/O) in J2SE 1.4, this scalability problem has been rectified by the introduction of a non-blocking I/O framework (though there are a number of open issues in the NIO API as implemented by Oracle).

The non-blocking IO framework, though considerably more complex than the original blocking IO framework, allows any number of "channels" to be handled by a single thread. The framework is based on the Reactor Pattern.

More Info

More information on the contents of the java.io package can be viewed on the Oracle website by clicking this link (http://docs.oracle.com/javase/7/docs/api/index.html).



Event Handling

The Java platform Event Model is the basis for event-driven programming on the Java platform.

Event-driven programming

No matter what the programming language or paradigm you are using, chances are that you will eventually run into a situation where your program will have to wait for an external event to happen. Perhaps your program must wait for some user input, or perhaps it must wait for data to be delivered over the network. Or perhaps something else. In any case, the program must wait for something to happen that is beyond the program's control: the program cannot make that event happen.

In this situation there are two general options for making a program wait for an external event to happen. The first of these is called polling and means you write a little loop of the for "while the event has not happened, check again". Polling is very simple to build and very straightforward. But it is also very wasteful: it means a program takes up processor time in order to do absolutely nothing but wait. This is usually considered too much of a drawback for programs that have to do a lot of waiting. Programs that have a lot of waiting moments (for example, programs that have a graphical user interface and often have to wait for long periods of time until the user does something) usually fare much better when they use the other mechanism: event-driven programming.

In event-driven programming a program that must wait, simply goes to sleep. It no longer takes up processor time, might even be unloaded from memory and generally leaves the computer available to do useful things. But the program doesn't completely go away; instead, it makes a deal with the computer or the operating system. A deal sort of like this:

Okay Mr. Operating System, since I have to wait for an event to happen, I'll go away and let you do useful work in the meantime. But in return, you have to let me know when my event has happened and let me come back to deal with it.

Event-driven programming usually has a pretty large impact on the design of a program. Usually, a program has to be broken up into separate pieces to do event-driven programming (one piece for general processing and one or more others to deal with events that occur). Event-driven programming in Java is more complicated than non-event driven but it makes far more efficient use of the hardware and sometimes (like when developing a graphical user interface) dividing your code up into event-driven blocks actually fits very naturally with your program's structure.

In this module we examine the basis of the Java Platform's facilities for event-driven programming and we look at some typical examples of how that basis has been used throughout the platform.

The Java Platform Event Model

Introduction

One of the most interesting things about support for event-driven programming on the Java platform is that there is none, as such. Or, depending on your point of view, there are many different individual pieces of the platform that offer their own support for event-driven programming.

The reason that the Java platform doesn't offer one general implementation of event-driven programming is linked to the origins of the support that the platform does offer. Back in 1996 the Java programming language was just getting started in the world and was still trying to gain a foothold and conquer a place for itself in software development. Part of this early development concentrated on software development tooling like IDEs. One of the trends in software development around that time was for reusable software components geared towards user interfaces: components that would encapsulate some sort of interesting, reusable functionality into a single package that could be handled as a single entity rather than as a loose collection of individual classes. Sun Microsystems tried to get on the component bandwagon by introducing what they called a JavaBean, a software component not only geared towards the UI but that could also be configured easily from an IDE. In order to make this happen Sun came up with a large specification of JavaBeans (the JavaBeans Spec) dealing mostly with naming conventions (to make the components easy to handle from an IDE). But Sun also realized at the same time that a UI-centric component would need support for an event-driven way of connecting events in the component to business logic that would have to be written by the individual developer. So the JavaBeans Spec also included a small specification for an event Model for the Java platform.

When they started working on this Event Model, the Sun engineers were faced with a choice: try to come up with a huge specification to encompass all possible uses of an event model, or just specify an abstract, generic framework that could be expanded for individual use in specific situations. They chose the latter option and so, love it or hate it, the Java Platform has no generic support for event-driven programming other than this general Event Model framework.

The Event Model framework

The basic Event Model framework

The Event Model framework is really very simple in and of itself, consisting of three classes (one abstract) and an interface. Most of all it consists of naming conventions that the programmer must obey. The framework is depicted in the image on the right.

Speaking in terms of classes and interfaces, the most important parts of the framework are the java.util.EventObject abstract class and the java.util.EventListener interface. These two types are the centerpieces of the rules and conventions of the Java Platform Event Model, which are:

  • A class that has to be notified when an event occurs, is called an event listener. An event listener has one distinct method for each type of event notification that it is interested in.
  • Event notification method declarations are grouped together into categories. Each category is represented by an event listener interface, which must extend java.util.EventListener. By convention an event listener interface is named <Event category name>Listener. Any class that will be notified of events must implement at least one listener interface.
  • Any and all state related to an event occurrence will be captured in a state object. The class of this object must be a subclass of java.util.EventObject and must record at least which object was the source of the event. Such a class is called an event class and by convention is named <Event category name>Event.
  • Usually (but not necessarily!) an event listener interface will relate to a single event class. An event listener may have multiple event notification methods that take the same event class as an argument.
  • An event notification method usually (but not necessarily!) has the conventional signature public void <specific event>(<Event category name>Event evt).
  • A class that is the source of events must have a method that allows for the registration of listeners, one for each possible listener interface type. These methods must by convention have the signature public void add<Event category name>Listener(<Event category name>Listener listener).
  • A class that is the source of events may have a method that allows for the deregistration of listeners, one for each possible listener interface type. These methods must by convention have the signature public void remove<Event category name>Listener(<Event category name>Listener listener).
A general example of how the framework is used

That seems like a lot, but it's pretty simple once you get used to it. Take a look at the image on the left, which contains a general example of how you might use the framework. In this example we have a class called EventSourceClass that publishes interesting events. Following the rules of the Event Model, the events are represented by the InterestingEvent class which has a reference back to the EventSourceClass object (source, inherited from java.util.EventObject).

Whenever an interesting event occurs, the EventSourceClass must notify all of the listeners for that event that it knows about by calling the notification method that exist for that purpose. All of the notification methods (in this example there is only one, interestingEventOccurred) have been grouped together by topic in a listener interface: InterestingEventListener, which implements java.util.EventListener and is named according to the Event Model conventions. This interface must be implemented by all event listener classes (in this case only InterestingEventListenerImpl). Because EventSourceClass must be able to notify any interested listeners, it must be possible to register them. For this purpose the EventSourceClass has an addInterestingEventListener method. And since it is required, there is a removeInterestingEventListener method as well.

As you can clearly see from the example, using the Event Model is mostly about following naming conventions. This might seem a little cumbersome at first, but the point of having naming conventions is to allow automated tooling to access and use the event model. And there are indeed many tools, IDEs and frameworks that are based on these naming conventions.

Degrees of freedom in the Model

There's one more thing to notice about the Event Model and that is what is not in the Model. The Event Model is designed to allow implementations a large degree of freedom in the implementation choices made, which means that the Event Model can serve as the basis for a very wide range of specific, purpose-built event handling systems.

Aside from naming conventions and some base classes and interfaces, the Event Model specifies the following:

  • It must be possible to register and deregister listeners.
  • An event source must publish events by calling the correct notification method on all registered listeners.
  • A call to an event notification method is a normal, synchronous Java call and the method must be executed by the same thread that called it.

But the Event Model doesn't specify how any of this must be done. There are no rules regarding which classes exactly must be event sources, nor about how they must keep track of registered event listeners. So one class might publish its own events, or be responsible for publishing the events that relate to an entire collection of objects (like an entire component). And an event source might allow listeners to be deregistered at any time (even in the middle of handling an event) or might limit this to certain times (which is relevant to multithreading).

Also, the Event Model doesn't specify how it must be embedded within any program. So, while the model specifies that a call to an event handling method is a synchronous call, the Model does not prescribe that the event handling method cannot hand off tasks to another thread or that the entire event model implementation must run in the main thread of the application. In fact, the Java Platform's standard user interface framework (Swing) includes an event handling implementation that runs as a complete subsystem of a desktop application, in its own thread.

Event notification methods, unicast event handling and event adaptors

In the previous section we mentioned that an event notification method usually takes a single argument. This is the preferred convention, but the specification does allow for exceptions to this rule if the application really needs that exception. A typical case for an exception is when the event notification must be sent across the network to a remote system though non-Java means, like the CORBA standard. In this case it is required to have multiple arguments and the Event Model allows for that. However, as a general rule the correct format for a notification method is

Example Code section 1.1: Simple notification method
public void specificEventDescription(Event_type evt)

Another thing we mentioned earlier is that, as a general rule, the Event Model allows many event listeners to register with a single event source for the same event. In this case the event source must broadcast any relevant events to all the registered listeners. However, once again the Event Model specification allows for an exception to the rule. If it is necessary from a design point of view you may limit an event source to registering a single listener; this is called unicast event listener registration. When unicast registration is used, the registration method must be declared to throw the java.util.TooManyListenersException exception if too many listeners are registered:

Example Code section 1.2: Listener registration
public void add<Event_type>Listener(<Event_type>Listener listener) throws java.util.TooManyListenersException
An event adaptor in between the event source and the event listener.

Finally, the specification allows for one more extension: the event adaptor. An event adaptor is an implementation of an event listener interface that can be inserted between an event source and an actual event listener class. This is done by registering the adaptor with the event source object using the regular registration method. Adaptors are used to add additional functionality to the event handling mechanism, such as routing of event objects, event filtering or enriching of the event object before processing by an actual event handler class.

A simple example

In the previous section we've explored the depths (such as there are) of the Java platform Event Model framework. If you're like most people, you've found the theoretical text more confusing than the actual use of the model. Certainly more confusing than should be necessary to explain what is, really, quite a simple framework.

In order to clear everything up a bit, let's examine a simple example based on the Event Model framework. Let's assume that we want to write a program that reads a stream of numbers input by the user at the command line and processes this stream somehow. Say, by keeping track of the running sum of numbers and producing that sum once the stream has been completely read.

Of course we could implement this program quite simply with a loop in a main() method. But instead let's be a little more creative. Let's say that we want to divide our program neatly into classes, each with a responsibility of its own (like we should in a proper, object-oriented design). And let's imagine that we want it to be possible not only to calculate the sum of all the numbers read, but to perform any number of calculations on the same number stream. In fact, it should be possible to add new calculations with relative ease and without having to affect any previously existing code.

If we analyze these requirements, we come to the conclusion that we have a number of different responsibilities in the program:

  • Reading the number stream from the command line
  • Processing the number stream (possibly multiple of these)
  • Starting the entire program

Using the Event Model framework allows us to separate the two main responsibilities cleanly and affords us the flexibility we are looking for. If we implement the logic for reading the number stream in a single class and treat the reading of a single number as an event, the Event Model allows us to broadcast that event (and the number) to as many stream processors as we like. The class for reading the number stream will act as the event source of the program and each stream processor will be a listener. Since each listener is a class of its own and can be registered with the stream reader (or not) this means our model allows us to have multiple, independent stream processing that we can add on to without affecting the code to read the stream or any pre-existing stream processor.

The Event Model says that any state associated with an event should be included in a class that represents the event. That's perfect for us; we can implement a simple event class that will record the number read from the command line. Each listener can then process this number as it sees fit.

For our interesting event set let's keep things simple: let's limit ourselves to having read a new number and having reached the end of the stream. With this choice we come to the following design for our example application:

JavaEventModelWikibooksJavaProgrammingBookExample.jpg

In the following sections we look at the implementation of this example.

Example basics

Let's start with the basics. According to the Event Model rules, we must define an event class to encapsulate our interesting event. We should call this class something-somethingEvent. Let's go for NumberReadEvent, since that's what will interest us. According to the Model rules, this class should encapsulate any state that belongs with an event occurrence. In our case, that's the number read from the stream. And our event class must inherit from java.util.EventObject. So all in all, the following class is all we need:

Computer code Code listing 1.1: NumberReadEvent.
package org.wikibooks.en.javaprogramming.example;

import java.util.EventObject;

public class NumberReadEvent extends EventObject {

    private double number;
   
    public NumberReadEvent(Object source, Double number) {
        super(source);
        this.number = number;
    }

    public double getNumber() {
        return number;
    }
}

Next, we must define a listener interface. This interface must define methods for interesting events and must extend java.util.EventListener. We said earlier our interesting events were "number read" and "end of stream reached", so here we go:

Computer code Code listing 1.2: NumberReadListener.
package org.wikibooks.en.javaprogramming.example;

import java.util.EventListener;

public interface NumberReadListener extends EventListener {
    public void numberRead(NumberReadEvent numberReadEvent);
   
    public void numberStreamTerminated(NumberReadEvent numberReadEvent);
}

Actually the numberStreamTerminated method is a little weird, since it isn't actually a "number read" event. In a real program you'd probably want to do this differently. But let's keep things simple in this example.

The event listener implementation

So, with our listener interface defined, we need one or more implementations (actual listener classes). At the very least we need one that will keep a running sum of the numbers read. We can add as many as we like, of course. But let's stick with just one for now. Obviously, this class must implement our NumberReadListener interface. Keeping a running summation is a matter of adding numbers to a field as the events arrive. And we wanted to report on the sum when the end of the stream is reached; since we know when that happens (i.e. the numberStreamTerminated method is called), a simple println statement will do:

Computer code Code listing 1.3: NumberReadListenerImpl.
package org.wikibooks.en.javaprogramming.example;

public class NumberReadListenerImpl implements NumberReadListener {
   
    double totalSoFar = 0D;

    @Override
    public void numberRead(NumberReadEvent numberReadEvent) {
        totalSoFar += numberReadEvent.getNumber();
    }

    @Override
    public void numberStreamTerminated(NumberReadEvent numberReadEvent) {
        System.out.println("Sum of the number stream: " + totalSoFar);
    }
}

So, is this code any good? No. It's yucky and terrible and most of all not thread safe. But it will do for our example.

The event source

This is where things get interesting: the event source class. This is the interesting place because this is where we must put code to read the number stream, code to send events to all the listeners and code to manage listeners (add and remove them and keep track of them).

Let's start by thinking about keeping track of listeners. Normally this is a tricky business, since you have to take all sorts of multithreading concerns into account. But we're being simple in this example, so let's just stick with a simple java.util.Set of listeners. Which we can initialize in the constructor:

Example Code section 1.1: The constructor
private Set<NumberReadListener> listeners;
   
public NumberReader() {
    listeners = new HashSet<NumberReadListener>();
}

That choice makes it really easy to implement adding and removing of listeners:

Example Code section 1.2: The register/deregister
public void addNumberReadListener(NumberReadListener listener) {
    this.listeners.add(listener);
}

public void removeNumberReadListener(NumberReadListener listener) {
    this.listeners.remove(listener);
}

We won't actually use the remove method in this example — but recall that the Model says it must be present.

Another advantage of this simple choice is that notification of all the listeners is easy as well. We can just assume any listeners will be in the set and iterate over them. And since the notification methods are synchronous (rule of the model) we can just call them directly:

Example Code section 1.3: The notifiers
private void notifyListenersOfEndOfStream() {
    for (NumberReadListener numberReadListener : listeners) {
        numberReadListener.numberStreamTerminated(new NumberReadEvent(this, 0D));
    }
}

private void notifyListeners(Double d) {
    for (NumberReadListener numberReadListener: listeners) {
        numberReadListener.numberRead(new NumberReadEvent(this, d));
    }
}

Note that we've made some assumptions here. For starters, we've assumed that we'll get the Double value d from somewhere. Also, we've assumed that no listener will ever care about the number value in the end-of-stream notification and have passed in the fixed value 0 for that event.

Finally we must deal with reading the number stream. We'll use the Console class for that and just keep on reading numbers until there are no more:

Example Code section 1.4: The main method
public void start() {
    Console console = System.console();
    if (console != null) {
        Double d = null;
        do {
            String readLine = console.readLine("Enter a number: ", (Object[])null);
            d = getDoubleValue(readLine);
            if (d != null) {
                notifyListeners(d);
            }
        } while (d != null);
        notifyListenersOfEndOfStream();
    }
}

Note how we've hooked the number-reading loop into the event handling mechanism by calling the notify methods? The entire class looks like this:

Computer code Code listing 1.4: NumberReader.
package org.wikibooks.en.javaprogramming.example;

import java.io.Console;
import java.util.HashSet;
import java.util.Set;

public class NumberReader {
    private Set<NumberReadListener> listeners;
   
    public NumberReader() {
        listeners = new HashSet<NumberReadListener>();
    }
   
    public void addNumberReadListener(NumberReadListener listener) {
        this.listeners.add(listener);
    }
   
    public void removeNumberReadListener(NumberReadListener listener) {
        this.listeners.remove(listener);
    }
   
    public void start() {
        Console console = System.console();
        if (console != null) {
            Double d = null;
            do {
                String readLine = console.readLine("Enter a number: ", (Object[])null);
                d = getDoubleValue(readLine);
                if (d != null) {
                    notifyListeners(d);
                }
            } while (d != null);
            notifyListenersOfEndOfStream();
        }
    }

    private void notifyListenersOfEndOfStream() {
        for (NumberReadListener numberReadListener: listeners) {
            numberReadListener.numberStreamTerminated(new NumberReadEvent(this, 0D));
        }
    }

    private void notifyListeners(Double d) {
        for (NumberReadListener numberReadListener: listeners) {
            numberReadListener.numberRead(new NumberReadEvent(this, d));
        }
    }

    private Double getDoubleValue(String readLine) {
        Double result;
        try {
            result = Double.valueOf(readLine);
        } catch (Exception e) {
            result = null;
        }
        return result;
    }
}

Running the example

Finally, we need one more class: the kickoff point for the application. This class will contain a main() method, plus code to create a NumberReader, a listener and to combine the two:

Computer code Code listing 1.5: Main.
package org.wikibooks.en.javaprogramming.example;

public class Main {

    public static void main(String[] args) {
        NumberReader reader = new NumberReader();
        NumberReadListener listener = new NumberReadListenerImpl();
        reader.addNumberReadListener(listener);
        reader.start();
    }
}

If you compile and run the program, the result looks somewhat like this:

Computer code An example run
>java org.wikibooks.en.javaprogramming.example.Main
Enter a number: 0.1
Enter a number: 0.2
Enter a number: 0.3
Enter a number: 0.4
Enter a number:

Computer code Output
Sum of the number stream: 1.0

Extending the example with an adaptor

Next, let's take a look at applying an adaptor to our design. Adaptors are used to add functionality to the event handling process that:

  • is general to the process and not specific to any one listener; or
  • is not supposed to affect the implementation of specific listeners.

According to the Event Model specification a typical use case for an adaptor is to add routing logic for events. But you can also add filtering or logging. In our case, let's do that: add logging of the numbers as "proof" for the calculations done in the listeners.

An adaptor, as explained earlier, is a class that sits between the event source and the listeners. From the point of view of the event source, it masquerades as a listener (so it must implement the listener interface). From the point of view of the listeners it pretends to be the event source (so it should have add and remove methods). In other words, to write an adaptor you have to repeat some code from the event source (to manage listeners) and you have to re-implement the event notification methods to do some extra stuff and then pass the event on to the actual listeners.

In our case we need an adaptor that writes the numbers to a log file. Keeping it simple once again, let's settle for an adaptor that:

  • Uses a fixed log file name and overwrites that log file with every program run.
  • Opens a FileWriter in the constructor and just keeps it open.
  • Implements the numberRead method by writing the number to the FileWriter.
  • Implements the numberStreamTerminated method by closing the FileWriter.

Also, we can make life easy on ourselves by just copying all the code we need to manage listeners over from the NumberReader class. Again, in a real program you'd want to do this differently. Note that each notification method implementation also passes the event on to all the real listeners:

Computer code Code listing 1.6: NumberReaderLoggingAdaptor.
package org.wikibooks.en.javaprogramming.example;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

public class NumberReaderLoggingAdaptor implements NumberReadListener {
    private Set<NumberReadListener> listeners;
    private BufferedWriter output;
   
    public NumberReaderLoggingAdaptor() {
        listeners = new HashSet<NumberReadListener>();
        try {
            output = new BufferedWriter(new FileWriter("numberLog.log"));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
   
    public void addNumberReadListener(NumberReadListener listener) {
        this.listeners.add(listener);
    }
   
    public void removeNumberReadListener(NumberReadListener listener) {
        this.listeners.remove(listener);
    }
   
   
    @Override
    public void numberRead(NumberReadEvent numberReadEvent) {
        try {
            output.write(numberReadEvent.getNumber() + "\n");
        } catch (Exception e) {
           
        }
        for (NumberReadListener numberReadListener: listeners) {
            numberReadListener.numberRead(numberReadEvent);
        }
    }

    @Override
    public void numberStreamTerminated(NumberReadEvent numberReadEvent) {
        try {
            output.flush();
            output.close();
        } catch (Exception e) {
           
        }
        for (NumberReadListener numberReadListener: listeners) {
            numberReadListener.numberStreamTerminated(numberReadEvent);
        }
    }

}

Of course, to make the adaptor work we have to make some changes to the bootstrap code:

Computer code Code listing 1.7: Main.
package org.wikibooks.en.javaprogramming.example;

public class Main {

    public static void main(String[] args) {
        NumberReader reader = new NumberReader();
        NumberReadListener listener = new NumberReadListenerImpl();
        NumberReaderLoggingAdaptor adaptor = new NumberReaderLoggingAdaptor();
        adaptor.addNumberReadListener(listener);
        reader.addNumberReadListener(adaptor);
        reader.start();
    }
}

But note how nicely and easily we can re-link the objects in our system. The fact that adaptors and listeners both implement the listener interface and the adaptor and event source both look like event sources means that we can hook the adaptor into the system without having to change a single statement in the classes that we developed earlier.

And of course, if we run the same example as given above, the numbers are now recorded in a log file.

Platform uses of the Event Model

The Event Model, as mentioned earlier, doesn't have a single all-encompassing implementation within the Java platform. Instead, the model serves as a basis for several different purpose-specific implementations, both within the standard Java platform and outside it (in frameworks).

Within the platform the main implementations are found in two areas:

  • As part of the JavaBeans classes, particularly in the support classes for the implementation of PropertyChangeListeners.
  • As part of the Java standard UI frameworks, AWT and Swing.



Canvas

An essential part of programming in Java requires you to build exciting new user interfaces for yourselves. Components that come built into the Java framework are regular UI elements, however for a more rich experience, you need controls of your own. Take, for instance, a charting application. No charting tool comes built into a Java API. You need to manually draw the chart yourself.

Coding drawing, to begin with, is pretty daunting but once you know the basics of Graphics programming in Java, you can create elegant graphics and art in no time. But the question that arises in one's mind is what to draw on. The answer to this question is simpler than it seems. You can start drawing on any component in the Java framework. Whether it be a panel, window or even a button.

Let me break it down for you. A component in the Java language is a class that has been derived from the Component class. Each component has a method with a signature paint(Graphics) which can be overridden to manually draw something atop it.

Overriding the paint(Graphics) method

Below is an example on how you need to override the above method. For this very example, the component class that we would be using would be the Canvas class. For more information about the Canvas class, see the section on Understanding the Canvas class

Computer code Code listing 9.1: Initializing a Canvas class
import java.awt.*;

public class MyCanvas extends Canvas {

    public MyCanvas() {
        //...
    }

    public void paint(Graphics graphics) {
        /* We override the method here. The graphics
         * code comes here within the method body. */
    }
}

Understanding the Canvas class

Code listing 9.1 shows the simplicity and power of the syntax for enabling the graphics functions within Java. Lets begin by understanding what a Canvas class does. A Canvas class is a derivative or a sub-class of the Component class and when placed over a Frame, displays as a blank area.

For the purpose of drawing graphics, you may use any other class derived from the Component class, for instance, JPanel or even JTextField or JButton. Why we use the Canvas class is purely to grasp the idea of drawing in Java.

Note:
Notice the J before the names of each class. This suggests that the classes are part of the Java Swing library. Swing enables more freedom in drawing expressions in Java than AWT.

Let us refine the above code for the class to be executable and the Canvas to be displayed. For this we will add an entry-point method namely the main(String[]) method in its body and calling a JFrame class to load the canvas on.

Computer code Code listing 9.2: Displaying a Canvas class atop a JFrame
import java.awt.*;
import javax.swing.*;

public class MyCanvas extends Canvas {
    public MyCanvas() {
    }

    public void paint(Graphics graphics) {
    }

    public static void main(String[] args) {
        // We initialize our class here
        MyCanvas canvas = new MyCanvas();
        JFrame frame = new JFrame();
        frame.setSize(400, 400);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        // Here we add it to the frame
        frame.getContentPane().add(canvas);
        frame.setVisible(true);
    }
}

The following code now helps our class to be executable and displays the canvas on top of the frame as it displays. Running this class would result in an empty frame, however it should be clear that the canvas is sitting atop it and is merely not displaying any drawings yet.

Figure 9.1: A blank canvas atop a JFrame

Get, set, draw!

Now that the basic structure of our program has been laid out, we need to explore how drawing is actually done by writing Java code. Move to the next section and try your hand at drawing basic shapes and lines. But whilst you are still fresh to the concept of a Canvas, why not test your knowledge. Try answering these questions below.

Question 9.1: What classes are used to draw in Java?

  1. Any class that is derived from the Object class.
  2. Any class that is derived from the Component class.
  3. None of the above.
Answer

2
A class derived from the Object class is not viable as a visible component, whereas a class derived from a Component class is a visible entity atop a Container hence a likely candidate for displaying drawings.

Question 9.2: What is the method that needs to be overridden in order to enable drawing?

  1. The main(String[]) method.
  2. The MyCanvas() method.
  3. The paint(Graphics) method.
  4. None of the above.
Answer

3
As discussed earlier the paint(Graphics) method is the correct option. The name says it all.



Graphics

Graphics - Drawing in Java



Graphics/Drawing shapes

Introduction to Graphics

Throughout this chapter, we will refer to the process of creating Graphical content with code as either drawing or painting. However, Java officially recognizes the latter as the proper word for the process, but we will differentiate between the two later on.

Now, the main class that you would be needing would, without doubt, be the Graphics class. If you take a closer look at the method that we used in theIdentifying the acquisition of the Graphics class in our code

Computer code Code listing 9.3: A basic canvas
import java.awt.*;
import javax.swing.*;
public class MyCanvas extends Canvas {
    public MyCanvas() {
    }

    public void paint(Graphics graphics) {
        /* We would be using this method only for the sake
         * of brevity throughout the current section. Note
         * that the Graphics class has been acquired along
         * with the method that we overrode. */
    }

    public static void main(String[] args) {
        MyCanvas canvas = new MyCanvas();
        JFrame frame = new JFrame();
        frame.setSize(400, 400);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(canvas);
        frame.setVisible(true);
    }
}

To view the contents of the Graphics class, please check the external links at the bottom of the page for links to the online API.

Etching a line on the canvas

Understanding coordinates

To start off your drawing experience, consider drawing the most basic shape — a line. A canvas when viewed upon with regards to drawing routines can be expressed as an inverted Cartesian coordinate system. A plane expressed by an x- and a y-axis. The origin point or being the top-left corner of a canvas and the visible area of the canvas being the Cartesian quadrant I or the positive-positive (+,+) quadrant. The further you go down from the top, the greater the value of y-coordinate on the y-axis, vice-versa for the x-axis as you move toward the right from the left. And unlike the values on a normal graph, the values appear to be positive. So a point at would be 10 pixels away from the left and 20 pixels away from the top, hence the format .

Figure 9.2: A simple line form displayed across the canvas from Code section 9.4

Drawing a simple line across the screen

Now, we already know that a line is a connection of two discreet points atop a canvas. So, if one point is at and the other is at , drawing a line would require you to write a syntax like code below. For the sake of brevity, we will skim out the rest of the method unused in the example.

Example Code section 9.4: Drawing a simple line form
...
public class MyCanvas extends Canvas {
    ...
    public void paint(Graphics graphics) {
        graphics.setColor(Color.black);
        graphics.drawLine(40, 30, 330, 380);
        
    }
    ...
}

In the above example, a simple method is used to define precisely where to place the line on the Cartesian scale of the canvas. The drawLine(int,int,int,int) asks you to put four arguments, appearing in order, the x1 coordinate, the y1 coordinate, the x2 coordinate and the y2 coordinate. Running the program will show a simple black line diagonally going across the canvas.

Figure 9.3: A simple black-outlined rectangle drawn

Drawing a simple rectangle

We now proceed on to our second drawing. A simple rectangle would do it justice, see below for code.

Example Code section 9.5: Drawing a simple rectangle
...
public class MyCanvas extends Canvas {
    ...
    public void paint(Graphics graphics) {
        graphics.drawRect(10, 10, 100, 100);
    }
    ...
}

In the above example, you see how easy it is to draw a simple rectangle using the drawRect(int, int, int, int) method in the Graphics instance that we obtained. Run the program and you will see a simple black outline of a rectangle appearing where once a blank canvas was.

The four arguments that are being passed into the method are, in order of appearance, the x-coordinate, the y-coordinate, width and the height. Hence, the resultant rectangle would start painting at the point on the screen 10 pixels from the left and 10 from the top and would be a 100 pixel wide and a 100 pixel in height. To save the argument here, the above drawing is that of a square with equal sides but squares are drawn using the same method and there is no such method as drawSquare(int, int, int)

Figure 9.4: Same rectangle drawn with a red outline

Playing around with colors

You can change the color of the outline by telling the Graphics instance the color you desire. This can be done as follows:

Example Code section 9.6: Changing the outline color of the rectangle
...
public class MyCanvas extends Canvas {
    ...
    public void paint(Graphics graphics) {
        graphics.setColor(Color.red);
        graphics.drawRect(100, 100, 500, 500);
    }
    ...
}

Running the program would render the same rectangle but with a red colored outline.

For the purposes of bringing color to our drawing, we used a method namely the setColor(Color) method. This method comes into force for all the drawing made after its call until another color is set. It asks for an argument of type Color. Now because you have no idea of how to actually instantiate a Color class, the class itself has a few built-in colors. Some built-in colors that you can use are mentioned below.

  • Color.red
  • Color.blue
  • Color.green
  • Color.yellow
  • Color.pink
  • Color.black
  • Color.white

Try running the program while coding changes to colors for a different colored outline each time. Play around a bit with more colors. Look for the Color class API documentation in the external links at the bottom of the page.

Figure 9.5: Same rectangle drawn with a red outline and a yellow fill

Filling up the area of the rectangle

Up until now, you have been able to draw a simple rectangle for yourself while asking a question silently, "why is the outline of the rectangle being painted rather the area as a whole?" The answer is simple. Any method that starts with drawXxxx(...) only draws the outline. To paint the area within the outline, we use the fillXxxx(...) methods. For instance, the code below would fill a rectangle with yellow color while having a red outline. Notice that the arguments remain the same.

Example Code section 9.7: Drawing a yellow rectangle with a red outline
...
public class MyCanvas extends Canvas {
    ...
    public void paint(Graphics graphics) {
        graphics.setColor(Color.yellow);
        graphics.fillRect(10, 10, 100, 100);
        graphics.setColor(Color.red);
        graphics.drawRect(10, 10, 100, 100);
    }
    ...
}


Figure 9.6: A white circle drawn with a blue outline

What about a circle?

Drawing a circle is ever so easy? It is the same process as the syntax above only that the word Rect is changed to the word Oval. And don't ask me why oval? You simply don't have the method drawCircle(int, int, int) as you don't have drawSquare(int, int, int). Following is the application of Graphics code to draw a circle just to whet your appetite.

Example Code section 9.8: Drawing a white circle with a blue outline
...
public class MyCanvas extends Canvas {
    ...
    public void paint(Graphics graphics) {
        graphics.setColor(new Color(0,0,255));
        graphics.drawOval(50, 50, 100, 100);
    }
    ...
}


A new form of a rectangle

Figure 9.7: A pink rounded rectangle with a red outline. Amazing!

Simple so far, isn't it? Of all the shapes out there, these two are the only shapes that you'd need to build for the moment. Complex graphics routines are required to build shapes like a rhombus, triangle, trapezium or a parallelogram. We would be tackling them later on in another section. However, on a last note I would leave you with another interesting shape - a combination of both ovals and rectangle. Think a rectangle with rounded corners, a Rounded Rectangle (RoundRect).

Example Code section 9.9: Drawing a pink rounded rectangle with a red outline
...
public class MyCanvas extends Canvas {
    ...
    public void paint(Graphics graphics) {
        graphics.setColor(Color.pink);
        graphics.fillRoundRect(10, 10, 100, 100, 5, 5);
        graphics.setColor(Color.red);
        graphics.drawRoundRect(10, 10, 100, 100, 5, 5);
    }
    ...
}

Notice that the syntax of the drawRoundRect(int, int, int, int, int, int) method is a bit different than the syntax for the simple rectangle drawing routine drawRect(int, int, int, int). The two new arguments added at the end are the width of the arc in pixels and the height of the arc in pixels. The result is pretty amazing when you run the program. You don't need to squint your eyes to tell that the corners of the rectangle are slightly rounded. The more the values of the width and height of the arcs, the more roundness appears to form around the corner.

Hmm, everything's perfect, but...

Sometimes people ask, after creating simple programs like the ones above, questions like:

  • Why did I have to tell the Graphics instance the color before each drawing routine? Why can't it remember my choice for the outlines and for the fill colors? The answer is simpler than it seems. But, to fully understand it, we need to focus on one little thing called the Graphics Context. The graphics context is the information that adheres to a single instance of the Graphics class. Such an instance remembers only one color at a time and that is why we need to make sure the context knows of the color we need to use by using the setColor(Color) method.
  • Can I manipulate the shapes, like tilt them and crop them? Hold your horses, cowboy! Everything is possible in Java, even tilting and cropping drawings. We will be focusing on these issues in a later section.
  • Is making shapes like triangles, rhombuses and other complex ones tedious? Well, to be honest here, you need to go back to your dusty book cabinet and take out that High School Geometry book because we would be covering some geometry basics while dealing with such shapes. Why not read a wikibook on Geometry?
Test your knowledge

Question 9.3: Throughout the exercise listings above, we have been filling the shapes first and then drawing their outlines. What happens if we do it the other way around? Consider the code below.

...
public void paint(Graphics graphics) {
    graphics.setColor(Color.red);
    graphics.drawRect(10, 10, 100, 100);
    graphics.setColor(Color.yellow);
    graphics.fillRect(10, 10, 100, 100);
}
...
  1. The left and the top outlines disappear.
  2. The right and the bottom outlines disappear.
  3. The color for the outline becomes the color for the fill area.
  4. All the outlines disappear.
Answer

All the outlines disappear.

Question 9.4: What would drawLine(10, 100, 100, 100) give you?

  1. A horizontal line.
  2. A vertical line.
  3. A diagonal line.
Answer

A horizontal line.

If you have any questions regarding the content provided here, please feel free to comment in this page's discussion.

External Links



Graphics/Drawing complex shapes

Computer code Code listing 9.4: Drawing complex shapes
public class Hello {
    JLabel label = newJLabel("Hello, Mundo!");
    JFrame frame = new JFrame("BK*");
    frame.add(label);

    frame.setSize(300, 300);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setVisible(true);
    frame.setLocationRelativeTo(null);
    frame.toFront();
    }
}



Graphics/Drawing text

Computer code Code listing 9.5: Drawing text
public class MyCanvas extends Canvas {
    public void init() {
        setFont("Times New Roman", Font.PLAIN, 24);
        setColor(Color.white);
        setBackGroundColor(Color.black);
        setLayout(new GridLayout());
 
        add(label);
        add(button);
    }
}



Applets



Applets/Overview

A Java applet is an applet delivered in the form of Java bytecode. Java applets can run in a Web browser using a Java Virtual Machine (JVM), or in Oracle's AppletViewer, a stand alone tool to test applets. Java applets were introduced in the first version of the Java language in 1995. Java applets are usually written in the Java programming language but they can also be written in other languages that compile to Java bytecode such as Jython.

Applets are used to provide interactive features to web applications that cannot be provided by HTML. Since Java's bytecode is platform independent, Java applets can be executed by browsers for many platforms, including Windows, Unix, Mac OS and Linux. There are open source tools like applet2app which can be used to convert an applet to a stand alone Java application/windows executable. This has the advantage of running a Java applet in off-line mode without the need for Internet browser software.

The Java applet is less and less used. You'd rather use JavaScript when it is possible.

First applet

The two things you must at least create is an HTML page and a Java class. It can be done on a local folder, no need to run a server but it will be harder to understand what is local, what is remote. The HTML page has to call the Java class using the <applet/> markup:

Computer code Code listing 9.3: HelloWorld.html
1 <!DOCTYPE html>
2 <html>
3   <body>
4     HTML content before the applet.<applet code="HelloWorld" height="40" width="200"></applet>HTML content after the applet.
5   </body>
6 </html>

Save this file on a folder. As the <applet/> markup is calling a Java class called HelloWorld, our class should be called HelloWorld.java:

Computer code Code listing 9.4: HelloWorld.java
 1 import java.applet.Applet;
 2 import java.awt.Graphics;
 3 
 4 public class HelloWorld extends Applet {
 5 
 6     /**
 7      * Print a message on the screen.
 8      */
 9     public void paint(Graphics g) {
10         g.drawString("Hello, world!", 20, 10);
11     }
12 }

Save this file and compile the class on the same folder. Now let's open the web page on a browser:

Figure 9.8: Java applet HelloWorld.

We clearly see that "Hello, world!" is not rendered the same way as the rest of the page.

HTML code

See also applet markup.

To embed an applet in a HTML page, you have to insert a <applet/> markup. This markup can have several attributes:

code* The name of the main class to call. It could be the name of the class with or without the .class .
height The height of the area where the content of the applet can be rendered on the web page.
width The width of the area where the content of the applet can be rendered on the web page.
archive The name of a compressed zip archive having .jar extension. The archive can contain all the needed classes to run the applet. Applets are usually delivered in this form, to minimize the download time.

The attributes with * are mandatory.

There have been some discussions about the usage of applet tag but it still can be used for beginning and also would work in the real world as well.

Java source code

Applets are not constructed in the same way as other classes or main programs. The entry point is different and the main class should extend the Applet class. The Applet class has four methods that can be called by the browser and you can redefine:

init() Called when the browser first loads the applet. It is only called once by browser execution.
start() Called when the applet starts running. It is called as many times as the user visits the web page.
stop() Called when the applet stops running. It is called as many times as the user visits the web page.
destroy() Called when the user quits the browser. It is only called once by browser execution.
paint() Called when the applet needs to be rendered, for example, when the browser is resized.

The four first methods define the lifecycle of an applet. At least init() or paint() must be redefined. The HTML applet tag can be embedded in the applet source code to allow the applet to be run directly by a simple applet viewer, without the need for an .html file. Typically, the applet tag immediately follows the import statements. It must be enclosed by /* */ comments:

Example Code section 9.10: MyApplet comment
1  /*
2  <applet code="MyApplet.class"> </applet>
3  */



Applets/User Interface

The main difference between an applet and a regular command-line executed program is that applets allow for extensible Graphical User Interfaces (GUI).

Since applets provide for the ability to create complex GUI, it is important for developers to know how to create such programs.

Applying styles and adding content

In Java applets, graphical portions are initialized and added in two different areas. While objects are initialized in the main class, they are added to the layout of the applet in the init() method. This is done using the syntax of add(<object>). A typical init() method looks something like this:

Example Code section 9.8: A typical init() method
 1 ...
 2 
 3 public void init() {
 4     setFont(new Font("Times New Roman", Font.PLAIN, 24));
 5     setForeground(Color.white);
 6     setBackground(Color.black);
 7     setLayout(new GridLayout);
 8    
 9     ...
10    
11     add(label);
12     add(button);
13 }

The different aspects of this method will be covered below.

Button

Lots of applets use buttons. There are only a few ways to have contact between the applet and the user, and the use of buttons is one of those ways. Buttons are created the same way as most other Java applet objects:

Example Code section 9.9: Button creation
1 Button submitButton = new Button("Submit");

When initializing a button, it is necessary to define what text will appear on that button in the given parameter. In this example, the button is initialized with the word "Submit" printed on it. Adding the button to the actual layout is done in the init() method, as described above.

Example Code section 9.10: Button display
1 public void init() {
2    
3     ...
4    
5     add(submitButton);
6 }

Allowing buttons to carry out tasks or utilize a user's input is a bit more complicated. These functions require an ActionListener, and will be discussed in ActionListener section.


Label

Labels are areas in applets that contain text which can not be edited by the user. This is usually ideal for descriptions (i.e. "Insert name:"). Labels are initialized and added to applet layouts in the same way as buttons. Also, like buttons, the text inside labels must be identified at initialization. If, however, the label will receive its text as the cause of a later function and should start off blank, no text should be placed between the quotation marks.

Example Code section 9.11: Label display
1 Label nameLabel = new Label("Name: ");
2 
3 ...
4 
5 public void init() {
6     add(nameLabel);
7 }


TextField

TextFields are areas in applets that allow users to insert text. The two parameters, which are optional, for TextFields can set predefined text in the field or set the number of columns allowed in the TextField. Here are a few examples:

Example Code section 9.12: Text field creation
 1     TextField t1 = new TextField();                // Blank
 2     TextField t2 = new TextField(5);               // Blank in 5 columns
 3     TextField t3 = new TextField("Input here");    // Predefined text
 4     TextField t4 = new TextField("Input here", 5); // Predefined text in 5 columns
 5 
 6     ...
 7 
 8     public void init() {
 9         add(t1);
10         add(t2);
11         add(t3);
12         add(t4);
13         ...
14     }


Font

Using stylish fonts in your Java applets may be necessary to help keep your Java applets attractive. The setFont() allows for either the font used throughout the applet to be defined or for one element's font to be set at a time.

The syntax for setting a font is setFont(<fontName>, <fontStyle>, <fontSize>).

To make every font in the applet plain, size 24 Times New Roman, the following code should be used:

Example Code section 9.13: Font setting
1 Font f = new Font("Times New Roman", Font.PLAIN, 24);
2 setFont(f);

It is not necessary to initialize the font and set the font through two different lines of code.

Example Code section 9.14: Direct font setting
1 setFont(new Font("Times New Roman", Font.PLAIN, 24));

However, to make the font of element a plain, size 24 Times New Roman, and element b italicized, size 28 Times New Roman, the following code should be used:

Example Code section 9.15: Object font setting
1 a.setFont(new Font("Times New Roman", Font.PLAIN, 24));
2 b.setFont(new Font("Times New Roman", Font.ITALIC, 28));

To set the color of the fonts used in an applet, the setForeground(<color>) method is used. This method already includes some predefined colors which can be used by calling, for example, setForeground(Color.white). Here are all of the predefined colors:

  • Color.black
  • Color.blue
  • Color.cyan
  • Color.darkGray
  • Color.gray
  • Color.green
  • Color.red
  • Color.white
  • Color.yellow

To create a custom color, the RGB values of the color can be passed in as the color parameter. For example, if red were not a predefined color, one could use setForeground(new Color(255, 0, 0)) to define red.

Just as font styles, font colors can be applied to separate elements. The syntax follows the same pattern: a.setForeground(Color.white).

Layout

Layouts are what make applets visible. Without a layout, nothing would display. There are five different types of layouts to choose from — some are very simple while others are complex.

Flow Layout

This layout places components left to right, using as much space as is needed. The Flow Layout is the default layout for applets and, therefore, does not need to be set. However, for clarity, one can specify the applet layout as a Flow Layout by placing this line of code at the top of the init() method:

Example Code section 9.16: Flow Layout
1 setLayout(new FlowLayout());

The added components to the layout that follow will be placed on screen in order of which they are added.

Example Code section 9.17: Component display
1 public void init() {
2     setLayout(new FlowLayout());
3     add(nameLabel);
4     add(t1);
5     add(submitButton);
6 }

Assuming that these variables are defined the same as above, these lines of code will create the layout of an applet that is composed of a label, a text field, and a button. They will all appear on one line if the window permits. By changing the width of window, the Flow Layout will contract and expand the components accordingly.


Grid Layout

This layout arranges components in the form of the table (grid). The number of rows and columns in the grid is specified in the constructor. The other two parameters, if present, specify vertical and horizontal padding between components.

Computer code Code listing 9.4: GridLayoutApplet.java
 1 import java.applet.Applet;
 2 import java.awt.Button;
 3 import java.awt.GridLayout;
 4 import java.awt.Label;
 5 import java.awt.TextField;
 6 
 7 public class GridLayoutApplet extends Applet {
 8 
 9     Button submitButton = new Button("Submit");
10     TextField t1 = new TextField();                // Blank
11     TextField t2 = new TextField(5);               // Blank in 5 columns
12     TextField t3 = new TextField("Input here");    // Predefined text
13     TextField t4 = new TextField("Input here", 5); // Predefined text in 5 columns
14     Label nameLabel = new Label("Name: ");
15 
16     /**
17      * Init.
18      */
19     public void init() {
20         // 3 rows, 4 columns, 2 pixel spacing
21         setLayout(new GridLayout(3, 4, 2, 2));
22         add(nameLabel);
23         add(t1);
24         add(t2);
25         add(t3);
26         add(t4);
27         add(submitButton);
28     }
29 }


The items have been displayed in this order:

 1st   2nd 
 3th   4th 
 5th   6th 

We see that the layout has been configured to fill the grid left-to-right and then top-to-bottom and that the two last columns have been ignored (they don't even exist). They have been ignored because there are not enough items to fill them and the number of rows is prior to the number of columns. This means that when you specify a number of rows that is not zero, the number of columns is simply ignored. You should specify zero rows in order that the number of columns is taken into account.

A grid layout creates cells with equal sizes. So it can be used not only to display items as a grid but also to display two items with the same width or height.

Border Layout

This layout places one big component in the center and up till four components at the edges. When adding to the container with this layout, you need to specify the location as the second parameter like BorderLayout.CENTER for the center or one of the world directions for the edge (BorderLayout.NORTH points to the top edge).

Example Code section 9.19: Border layout
1 import java.awt.*;
2 
3 Container container = getContentPane();
4 container.setLayout(new BorderLayout());
5 
6 JButton b2 = new JButton("two");
7 // Add the button to the right edge.
8 container.add(b2, BorderLayout.EAST);
9 ...


If you have two components, it is not the same to put the first in the north and the second to the center as to put the first in the center and the second to the south. In the first case, the layout will calculate the size of the component and the second component will have all the space left. In the second case, it is the opposite.

Card Layout

A card stack

The card layout displays only one item at a time and is only interesting with interactivity. The other items are stored in a stack and the displayed item is one of the items of the stack. The name of the card layout is a reference to a playing card deck where you can see the card at the top of the stack and you can put a card on the top. The difference in the card layout is that the items in the stack keeps their order. When you use this layout, you must use this method to add items to the container, i.e. the applet:

void add(String itemId, Component item) Adds an item to the container and associate the item to the id.

The card layout has several methods to change the currently displayed item:

void first(Container container) Display the first item of the stack.
void next(Container container) Display the item of the stack that is located after the displayed item.
void previous(Container container) Display the item of the stack that is located before the displayed item.
void last(Container container) Display the last item of the stack.
void show(Container container, String itemId) Display an item by its id.
Computer code Code listing 9.5: CardLayoutApplet.java
 1 import java.applet.Applet;
 2 import java.awt.CardLayout;
 3 import java.awt.Label;
 4 
 5 public class CardLayoutApplet extends Applet {
 6 
 7     static final String COMPONENT_POSITION_TOP = "TOP";
 8     static final String COMPONENT_POSITION_MIDDLE = "MIDDLE";
 9     static final String COMPONENT_POSITION_BOTTOM = "BOTTOM";
10 
11     Label topLabel = new Label("At the top");
12     Label middleLabel = new Label("In the middle");
13     Label bottomLabel = new Label("At the bottom");
14 
15     /**
16      * Init.
17      */
18     public void init() {
19         setLayout(new CardLayout());
20         add(COMPONENT_POSITION_TOP, topLabel);
21         add(COMPONENT_POSITION_MIDDLE, middleLabel);
22         add(COMPONENT_POSITION_BOTTOM, bottomLabel);
23         ((CardLayout)getLayout()).show(this, COMPONENT_POSITION_MIDDLE);
24     }
25 }


Panel

The main benefit of the layouts is that you can combine them one into another and you can do that with a panel. A panel is a component that has other components inside. A panel can then be added to the top component (frame or applet) or to another panel and be placed itself as defined by layout and constraints of this parent component. It has its own layout and is normally used to place a group of related components like buttons, for instance:

Figure 9.16: Java applet example.
Test your knowledge

Question 9.5: We want to create a basic FTP (File Transfer Protocol) software which looks like this:

Application name
Tool
Tool
Tool
Tool
Tool
Tool
Tool
Tool
Tool
Local folder




Remote folder




Status bar

On the top, it should display the name of the software. Under the name, it should display tool buttons that are displayed from the left to the right and the sequence of buttons is wrapped if it reaches the right border. Under the buttons, it should display two lists of files. The widths of these two lists should be the same and they should use all the width of the application. Under these two lists, it should display a status bar.

Create this display on an applet.

Answer

First, we have to analyze the display. We have four separate areas of components:

  • The name area
  • The tool area
  • The folder area
  • The status area

So we have to first separate these areas and then we will split these areas into components.

Computer code Answer 9.5: Answer5.java
 1 import java.applet.Applet;
 2 import java.awt.BorderLayout;
 3 import java.awt.Button;
 4 import java.awt.FlowLayout;
 5 import java.awt.GridLayout;
 6 import java.awt.Label;
 7 import java.awt.Panel;
 8 
 9 public class Answer5 extends Applet {
10 
11     Label applicationNameLabel = new Label("Wikibooks FTP");
12     Button tool1Button = new Button("Tool");
13     Button tool2Button = new Button("Tool");
14     Button tool3Button = new Button("Tool");
15     Button tool4Button = new Button("Tool");
16     Button tool5Button = new Button("Tool");
17     Button tool6Button = new Button("Tool");
18     Button tool7Button = new Button("Tool");
19     Button tool8Button = new Button("Tool");
20     Button tool9Button = new Button("Tool");
21     Label localFolderLabel = new Label("5 files");
22     Label remoteFolderLabel = new Label("3 files");
23     Label statusBarLabel = new Label("Available");
24 
25     /**
26      * Init.
27      */
28     public void init() {
29         setLayout(new BorderLayout());
30 
31         // The application name
32         add(applicationNameLabel, BorderLayout.NORTH);
33 
34         // The center
35         Panel centerPanel = new Panel();
36         centerPanel.setLayout(new BorderLayout());
37 
38         // The buttons
39         Panel buttonPanel = new Panel();
40         buttonPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
41         buttonPanel.add(tool1Button);
42         buttonPanel.add(tool2Button);
43         buttonPanel.add(tool3Button);
44         buttonPanel.add(tool4Button);
45         buttonPanel.add(tool5Button);
46         buttonPanel.add(tool6Button);
47         buttonPanel.add(tool7Button);
48         buttonPanel.add(tool8Button);
49         buttonPanel.add(tool9Button);
50         centerPanel.add(buttonPanel, BorderLayout.CENTER);
51 
52         // The local and remote folders
53         Panel folderPanel = new Panel();
54         folderPanel.setLayout(new GridLayout(0, 2, 2, 2));
55         folderPanel.add(localFolderLabel);
56         folderPanel.add(remoteFolderLabel);
57         centerPanel.add(folderPanel, BorderLayout.SOUTH);
58 
59         add(centerPanel, BorderLayout.CENTER);
60 
61         // The status bar
62         add(statusBarLabel, BorderLayout.SOUTH);
63     }
64 }
  1. The totality of the components is put in a border layout so that we have three vertical areas of elements.
  2. The area in the north is the area of the title.
  3. The area in the center contains the buttons and the folders and will be split later.
  4. The area in the south is the area of the status bar.
  5. The area in the center is now split with a border layout into a button area in the center and a folder area in the south.
  6. The button area is then split with a flow layout.
  7. The folder area is now split with a grid layout.


We use a grid layout to display the folders to have the same width between the two components. We can't use a grid layout to separate the name, the buttons, the folders and the status bar as these areas have not the same height. The buttons must be at the center of the border layout as the number of row of buttons would be badly calculated and the last rows of buttons would not appear.



Applets/Event Listeners

An Event Listener, once set to an applet object, waits for some action to be performed on it, be it mouse click, mouse hover, pressing of keys, click of button, etc. The class you are using (e.g. JButton, etc.) reports the activity to a class set by the class using it. That method then decides on how to react because of that action, usually with a series of if statements to determine which action it was performed on. source.getSource() will return the name of the object that the event was performed on, while the source is the object passed to the function when the action is performed. Every single time the action is performed, it calls the method.

ActionListener

ActionListener is an interface that could be implemented in order to determine how a certain event should be handled. When implementing an interface, all methods in that interface should be implemented, ActionListener interface has one method to implement named actionPerformed().

The code listing 9.6 shows how to implement ActionListener:

Computer code Code listing 9.6: EventApplet.java
 1 import java.applet.Applet;
 2 import java.awt.Button;
 3 import java.awt.Container;
 4 import java.awt.Dialog;
 5 import java.awt.FlowLayout;
 6 import java.awt.Frame;
 7 import java.awt.Label;
 8 import java.awt.event.ActionEvent;
 9 import java.awt.event.ActionListener;
10 
11 public class EventApplet extends Applet {
12 
13     /**
14      * Init.
15      */
16     public void init() {
17         Button clickMeButton = new Button("Click me");
18 
19         final Applet eventApplet = this;
20 
21         ActionListener specificClassToPerformButtonAction = new ActionListener() {
22 
23             public void actionPerformed(ActionEvent event) {
24                 Dialog dialog = new Dialog(getParentFrame(eventApplet), false);
25                 dialog.setLayout(new FlowLayout());
26                 dialog.add(new Label("Hi!!!"));
27                 dialog.pack();
28                 dialog.setLocation(100, 100);
29                 dialog.setVisible(true);
30             }
31 
32             private Frame getParentFrame(Container container) {
33                 if (container == null) {
34                     return null;
35                 } else if (container instanceof Frame) {
36                     return (Frame) container;
37                 } else {
38                     return getParentFrame(container.getParent());
39                 }
40 
41             }
42         };
43         clickMeButton.addActionListener(specificClassToPerformButtonAction);
44 
45         add(clickMeButton);
46     }
47 }

When you compile and run the above code, the message "Hi!!!" will appear when you click on the button.

MouseListener

Applet mouse listener does not differ from the AWT mouse listener in general. When the mouse is in the applet area, the listener receives notifications about the mouse clicks and drags (if MouseListener is registered) and mouse movements (if MouseMotionListener is registered). As applets are often small, it is a common practice to let applet itself to implement the mouse listeners.



Applets/Graphics and Media

Painting

By overriding the update(Graphics g) and paint(Graphics g) methods of an Applet (or one of it's sub-components), you can have fairly direct control over the rendering of an Applet. The Graphics object provides various primitives for working for two-dimensional graphics.



Reflection

Reflection is a new concept in Java, and did not exist in classical compiled languages like C, and C++. The idea is to discover an object's attributes and its methods programmatically.


Reflection/Overview

Reflection is the mechanism by which Java exposes the features of a class during runtime, allowing Java programs to enumerate and access a class' methods, fields, and constructors as objects. In other words, there are object-based mirrors that reflect the Java object model, and you can use these objects to access an object's features using runtime API constructs instead of compile-time language constructs. Each object instance has a getClass() method, inherited from java.lang.Object, which returns an object with the runtime representation of that object's class; this object is an instance of the java.lang.Class, which in turn has methods that return the fields, methods, constructors, superclass, and other properties of that class. You can use these reflection objects to access fields, invoke methods, or instantiate instances, all without having compile-time dependencies on those features. The Java runtime provides the corresponding classes for reflection. Most of the Java classes that support reflection are in the java.lang.reflect package. Reflection is most useful for performing dynamic operations with Java — operations that are not hard-coded into a source program, but that are determined at run time. One of the most important aspects of reflection is dynamic class loading.

Example: Invoking a main method

One way to understand how reflection works is to use reflection to model how the Java Runtime Environment (JRE) loads and executes a class. When you invoke a Java program

Standard input or output Console

java fully-qualified-class-name arg0 ... argn

and pass it command line arguments, the JRE must

  1. put the command line arguments arg0 ... argn into a String[] array
  2. dynamically load the target class named by fully-qualified-class-name
  3. access the public static void main(String[]) method
  4. invoke the main method, passing the string array main String[].

Steps 2, 3, and 4 can be accomplished with Java reflection. Below is an example of loading the Distance class, locating the main method, (see Understanding a Java Program) and invoking it via reflection.

Example Code section 10.1: main() method invocation.
 1 public static void invokeMain()
 2    throws ClassNotFoundException,
 3    	ExceptionInInitializerError,
 4    	IllegalAccessException,
 5    	IllegalArgumentException,
 6    	InvocationTargetException,
 7    	NoSuchMethodException,
 8    	SecurityException {
 9    Class<?> distanceClass = Class.forName("Distance");
10    String[] points = {"0", "0", "3", "4"};
11    Method mainMethod = distanceClass.getMethod("main", String[].class);
12    Object result = mainMethod.invoke(null, (Object) points);
13 }

This code is obviously more complicated than simply calling

Example Code section 10.2: main() method calling.
1 Distance.main(new String[]{"0", "0", "3", "4"});

However, the main Java runtime does not know about the Distance class. The name of the class to execute is a runtime value. Reflection allows a Java program to work with classes even though the classes are not known when the program was written. Let's explore what the invokeMain method is doing. The first statement at line 9 is an example of dynamic class loading. The forName() method will load a Java class and return an instance of java.lang.Class that results from loading the class. In this case, we are loading the class "Distance" from the default package. We store the class object in the local variable distanceClass; its type is Class<?>. The second statement at line 10 simply creates a String array with the four command line arguments we wish to pass to the main method of the Distance class. The third statement at line 11 performs a reflection operation on the Distance class. The getMethod() method is defined for the Class class. It takes a variable number of parameters: the method name is the first parameter and the remaining parameters are the types of each of main's parameters. The method name is trivial: we want to invoke the main method, so we pass in the name "main". We then add a Class variable for each of the method parameters. main accepts one parameter (String[] args) so we add a single Class element representing the String[]. The getMethod method has a return type of java.lang.reflect.Method; we store the result in a local variable named mainMethod. Finally, we invoke the method by calling the invoke() method of the Method instance. This method's first parameter is the instance to invoke on, and the remaining parameters are for the invokee's parameters. Since we are invoking a static method and not an instance method, we pass null as the instance argument. Since we only have a single parameter we pass it as the second argument. However, we must cast the parameter to Object to indicate that the array is the parameter, and not that the parameters are in the array. See varargs for more details on this.

Example Code section 10.3: invoke() call.
1 Object result = mainMethod.invoke(null, arguments);

The invoke() method returns an Object that will contain the result that the reflected method returns. In this case, our main method is a void method, so we ignore the return type. Most of the methods in this short invokeMain method may throw various exceptions. The method declares all of them in its signatures. Here is a brief rundown of what might throw an exception:

  • Class.forName(String) will throw ClassNotFoundException, if the named class cannot be located.
  • Class.forName(String) will throw ExceptionInInitializerError, if the class could not be loaded due the static initializer throwing an exception or a static field's initialization throwing an exception.
  • Class.getMethod(String name, Class parameterTypes[]) will throw
    • NoSuchMethodException, if a matching method is not found, or is not public (use getDeclaredMethod to get a non-public method).
    • SecurityException, if a security manager is installed and calling the method would result in an access violation (for example, the method is in the sun.* package designed for internal use only).
  • Method.invoke(Object instance, Object... arguments) may throw:
    • IllegalAccessException, if this method is invoked in a manner that violates its access modifiers.
    • IllegalArgumentException for various reasons, including
      • passing an instance that does not implement this method.
      • the actual arguments do not match the method's arguments
    • InvocationTargetException, if the underlying method (main in this case) throws an exception.

In addition to these exceptions, there are also errors and runtime exceptions that these methods may throw.


Reflection/Dynamic Class Loading

Dynamic Class Loading allows the loading of java code that is not known about before a program starts. Many classes rely on other classes and resources such as icons which make loading a single class unfeasible. For this reason the ClassLoader (java.lang.ClassLoader) is used to manage all the inner dependencies of a collection of classes. The Java model loads classes as needed and doesn't need to know the name of all classes in a collection before any one of its classes can be loaded and run.

Simple Dynamic Class Loading

An easy way to dynamically load a Class is via the java.net.URLClassLoader class. This class can be used to load a Class or a collection of classes that are accessible via a URL. This is very similar to the -classpath parameter in the java executable. To create a URLClassLoader, use the factory method (as using the constructor requires a security privilege):

Example Code section 10.4: Class loader.
1 URLClassLoader classLoader = URLClassLoader.newInstance(
2    new URL[]{"http://example.com/javaClasses.jar"});

Unlike other dynamic class loading techniques, this can be used even without security permission provided the classes come from the same Web domain as the caller. Once a ClassLoader instance is obtained, a class can be loaded via the loadClass method. For example, to load the class com.example.MyClass, one would:

Example Code section 10.5: Class loading.
1 Class<?> clazz = classLoader.load("com.example.MyClass");

Executing code from a Class instance is explained in the Dynamic Invocation chapter.


Reflection/Dynamic Invocation

We start with basic transfer object:

Computer code Code listing 10.1: DummyTo.java
 1 package com.test;
 2  
 3 public class DummyTo {
 4     private String name;
 5     private String address;
 6  
 7     public String getName() {
 8         return name;
 9     }
10  
11     public void setName(String name) {
12         this.name = name;
13     }
14  
15     public String getAddress() {
16         return address;
17     }
18  
19     public void setAddress(String address) {
20         this.address = address;
21     }
22  
23     public DummyTo(String name, String address) {
24         this.name = name;
25         this.address = address;
26     }
27  
28     public DummyTo() {
29         this.name = new String();
30         this.address = new String();
31     }
32  
33     public String toString(String appendBefore) {
34         return appendBefore + " " + name + ", " + address;
35     }
36 }

Following is the example for invoking method from the above mentioned to dynamically. Code is self explanatory.

Computer code Code listing 10.2: ReflectTest.java
 1 package com.test;
 2  
 3 import java.lang.reflect.Constructor;
 4 import java.lang.reflect.InvocationTargetException;
 5 import java.lang.reflect.Method;
 6  
 7 public class ReflectTest {
 8     public static void main(String[] args) {
 9         try {
10             Class<?> dummyClass = Class.forName("com.test.DummyTo");
11  
12             // parameter types for methods
13             Class<?>[] partypes = new Class[]{String.class};
14  
15             // Create method object. methodname and parameter types
16             Method meth = dummyClass.getMethod("toString", partypes);
17  
18             // parameter types for constructor
19             Class<?>[] constrpartypes = new Class[]{String.class, String.class};
20  
21             //Create constructor object. parameter types
22             Constructor<?> constr = dummyClass.getConstructor(constrpartypes);
23  
24             // create instance
25             Object dummyto = constr.newInstance(new Object[]{"Java Programmer", "India"});
26  
27             // Arguments to be passed into method
28             Object[] arglist = new Object[]{"I am"};
29  
30             // invoke method!!
31             String output = (String) meth.invoke(dummyto, arglist);
32             System.out.println(output);
33  
34         } catch (ClassNotFoundException e) {
35             e.printStackTrace();
36         } catch (SecurityException e) {
37             e.printStackTrace();
38         } catch (NoSuchMethodException e) {
39             e.printStackTrace();
40         } catch (IllegalArgumentException e) {
41             e.printStackTrace();
42         } catch (IllegalAccessException e) {
43             e.printStackTrace();
44         } catch (InvocationTargetException e) {
45             e.printStackTrace();
46         } catch (InstantiationException e) {
47             e.printStackTrace();
48         }
49     }
50 }
Standard input or output Console for Code listing 10.2
I am Java Programmer, India

Conclusion: Above examples demonstrate the invocation of method dynamically using reflection.


Reflection/Accessing Private Features with Reflection

All features of a class can be obtained via reflection, including access to private methods & variables. But not always see [6]. Let us look at the following example:

Computer code Code listing 10.3: Secret.java
1 public class Secret {
2   private String secretCode = "It's a secret";
3  
4   private String getSecretCode() {
5     return secretCode;     
6   }
7 }

Although the field and method are marked private, the following class shows that it is possible to access the private features of a class:

Computer code Code listing 10.4: Hacker.java
 1 import java.lang.reflect.Field;
 2 import java.lang.reflect.InvocationTargetException;
 3 import java.lang.reflect.Method;
 4  
 5 public class Hacker {
 6  
 7    private static final Object[] EMPTY = {};
 8  
 9    public void reflect() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
10      Secret instance = new Secret();
11      Class<?> secretClass = instance.getClass();
12  
13      // Print all the method names & execution result
14      Method methods[] = secretClass.getDeclaredMethods();
15      System.out.println("Access all the methods");
16      for (Method method : methods) {
17         System.out.println("Method Name: " + method.getName());
18         System.out.println("Return type: " + method.getReturnType());
19         method.setAccessible(true);
20         System.out.println(method.invoke(instance, EMPTY) + "\n");
21      }
22  
23      // Print all the field names & values
24      Field fields[] = secretClass.getDeclaredFields();
25      System.out.println("Access all the fields");
26      for (Field field : fields) {
27         System.out.println("Field Name: " + field.getName());
28         field.setAccessible(true);
29         System.out.println(field.get(instance) + "\n");
30      }
31   }
32  
33   public static void main(String[] args) {
34     Hacker newHacker = new Hacker();
35  
36     try {
37       newHacker.reflect();
38     } catch (Exception e) {
39       e.printStackTrace();
40     }
41   }
42 }
Standard input or output Console for Code listing 10.4
Access all the methods
Method Name: getSecretCode
Return type: class java.lang.String
It's a secret
Access all the fields
Field Name: secretCode
It's a secret


JUnit - Test Private methods

JUnit's are unit test cases, used to test the Java programs. Now you know how to test a private method using Reflection in JUnit. There's a long-standing debate on whether testing private members is a good habit[1];There are cases where you want to make sure a class exhibited the right behavior while not making the fields that need checking to assert that public (as it's generally considered bad practice to create accessors to a class just for the sake of a unit test). There are also cases when you can greatly simplify a test case by using reflection to test all smaller private methods (and their various branches), then test the main function. With dp4j it is possible to test private members without directly using the Reflection API but simply accessing them as if they were accessible from the testing method; dp4j injects the needed Reflection code at compile-time[2].

  1. What's the best way of unit testing private methods?, March 7, 2011
  2. Reflection API injected at compile-time


Advanced topics

Networking

Prior to modern networking solutions there existed workstations that were connected to a massive Mainframe computer that was solely responsible for memory management, processes and almost everything. The workstations would just render the information sent in from the Mainframe console.

But in the mid 90's, with the prices of Unix servers dropping, the trend was moving away from Mainframe computing toward Client-Server computing. This would enable rich clients to be developed on workstations while they would communicate with a centralized server, serving computers connected to it, to either communicate with other workstations also connected to it or it would request for database access or business logic stored on the server itself. The workstations were called clients.

This form of computing gave rise to the notion of the Front-end and Back-end programming. In it's hey-day, Java came up with different ways of making networking between computers possible. In this chapter, we would be looking at some of these ways. Listed below are two of the frameworks that Java uses to enable network programming. We would be exploring both of these in this chapter.

Client-Server programming

  1. 0% developed  as of Sep 22, 2007 Networking basics
  2. 0% developed  as of Sep 22, 2007 Creating a simple server
  3. 0% developed  as of Sep 22, 2007 Listening for clients
  4. 0% developed  as of Sep 22, 2007 Creating a client to interact with the server
  5. 0% developed  as of Sep 22, 2007 Sending information over a network
  6. 0% developed  as of Sep 22, 2007 Building complex carriage routines

Remote Method Invocation (RMI)

  1. 0% developed  as of Sep 22, 2007 Basics of Remote Method Invocation
  2. 0% developed  as of Sep 22, 2007 Of stubs and proxies


Database Programming

Regular Expressions

The regular expressions (regex) are provided by the package java.util.regex.

Researches

The Pattern class offers the function matches which returns true if an expression is found into a string.

For example, this script returns the unknown word preceding a known word:

import java.util.regex.Pattern;
public class Regex {
	public static void main(String[] args) {
		String s = "Test Java regex for Wikibooks.";
		System.out.println(Pattern.matches("[a-z]* Wikibooks",s));
    }
}
// Displays: "for Wikibooks"


The Matcher class allows to get all matches for a given expression, with different methods:

  1. find(): find the next result.
  2. group(): displays the result.

For example, this script displays the HTML b tags contents:

import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class Regex {
	public static void main(String[] args) {
		String s = "Test <i>Java</i> <b>regex</b> for <b>Wikibooks</b>.";
		Pattern p = Pattern.compile("<b>([^<]+)</b>");
		Matcher m = p.matcher(s);
		while(m.find()) {
			System.out.println(m.group());
			System.out.println(m.group(1));
		}
	}
}
/* Displays:
 <b>regex</b>
 regex
 <b>Wikibooks</b>
 Wikibooks
*/

Replacements


Libraries

Libraries, Extensions, and Frameworks


3D Programming

Although Java comes with the Java 3D library other libraries have been developed over time with similar functionality. Thus, unlike many other areas of Java development explored in this book, a Java programmer has a choice to make as to which 3D library to use.

3D graphics Java libraries


Java Native Interface

The Java Native Interface (JNI) enables Java code running in a Java Virtual Machine (JVM) to call and to be called by native applications (programs specific to a hardware and operating system platform) and libraries written in other languages, such as C, C++ and assembly.

JNI can be used:

  • To implement or use features that are platform-specific.
  • To implement or use features that the standard Java class library does not support.
  • To enable an existing application—written in another programming language—to be accessible to Java applications.
  • To let a native method use Java objects in the same way that Java code uses these objects (a native method can create Java objects and then inspect and use these objects to perform its tasks).
  • To let a native method inspect and use objects created by Java application code.
  • For time-critical calculations or operations like solving complicated mathematical equations (native code may be faster than JVM code).

On the other hand, an application that relies on JNI loses the platform portability Java offers. So you will have to write a separate implementation of JNI code for each platform and have Java detect the operating system and load the correct one at runtime. Many of the standard library classes depend on JNI to provide functionality to the developer and the user (file I/O, sound capabilities...). Including performance- and platform-sensitive API implementations in the standard library allows all Java applications to access this functionality in a safe and platform-independent manner. Only applications and signed applets can invoke JNI. JNI should be used with caution. Subtle errors in the use of JNI can destabilize the entire JVM in ways that are very difficult to reproduce and debug. Error checking is a must or it has the potential to crash the JNI side and the JVM.

This page will only explain how to call native code from JVM, not how to call JVM from native code.

Calling native code from JVM

In the JNI framework, native functions are implemented in separate .c or .cpp files. C++ provides a slightly simpler interface with JNI. When the JVM invokes the function, it passes a JNIEnv pointer, a jobject pointer, and any Java arguments declared by the Java method. A JNI function may look like this:

 JNIEXPORT void JNICALL Java_ClassName_MethodName
   (JNIEnv *env, jobject obj)
 {
     /*Implement Native Method Here*/
 }

The env pointer is a structure that contains the interface to the JVM. It includes all of the functions necessary to interact with the JVM and to work with Java objects. Example JNI functions are converting native arrays to/from Java arrays, converting native strings to/from Java strings, instantiating objects, throwing exceptions, etc. Basically, anything that Java code can do can be done using JNIEnv, albeit with considerably less ease.

On Linux and Solaris platforms, if the native code registers itself as a signal handler, it could intercept signals intended for the JVM. Signal chaining should be used to allow native code to better interoperate with JVM. On Windows platforms, Structured Exception Handling (SEH) may be employed to wrap native code in SEH try/catch blocks so as to capture machine (CPU/FPU) generated software interrupts (such as NULL pointer access violations and divide-by-zero operations), and to handle these situations before the interrupt is propagated back up into the JVM (i.e. Java side code), in all likelihood resulting in an unhandled exception.

C++ code

For example, the following converts a Java string to a native string:

 extern "C"
 JNIEXPORT void JNICALL Java_ClassName_MethodName
   (JNIEnv *env, jobject obj, jstring javaString)
 {
     //Get the native string from javaString
     const char *nativeString = env->GetStringUTFChars(javaString, 0);

     //Do something with the nativeString

     //DON'T FORGET THIS LINE!!!
     env->ReleaseStringUTFChars(javaString, nativeString);
 }

The JNI framework does not provide any automatic garbage collection for non-JVM memory resources allocated by code executing on the native side. Consequently, native side code (such as C, C++, or assembly language) must assume the responsibility for explicitly releasing any such memory resources that it itself acquires.

C code

 JNIEXPORT void JNICALL Java_ClassName_MethodName
   (JNIEnv *env, jobject obj, jstring javaString)
 {
     /*Get the native string from javaString*/
     const char *nativeString = (*env)->GetStringUTFChars(env, javaString, 0);

     /*Do something with the nativeString*/

     /*DON'T FORGET THIS LINE!!!*/
     (*env)->ReleaseStringUTFChars(env, javaString, nativeString);
 }

Note that C++ JNI code is syntactically slightly cleaner than C JNI code because like Java, C++ uses object method invocation semantics. That means that in C, the env parameter is dereferenced using (*env)-> and env has to be explicitly passed to JNIEnv methods. In C++, the env parameter is dereferenced using env-> and the env parameter is implicitly passed as part of the object method invocation semantics.

Objective-C code

 JNIEXPORT void JNICALL Java_ClassName_MethodName(JNIEnv *env, jobject obj, jstring javaString)
 {
     /*DON'T FORGET THIS LINE!!!*/
     JNF_COCOA_ENTER(env);

     /*Get the native string from javaString*/
     NSString* nativeString = JNFJavaToNSString(env, javaString);

     /*Do something with the nativeString*/

     /*DON'T FORGET THIS LINE!!!*/
     JNF_COCOA_EXIT(env);
 }

JNI also allows direct access to assembly code, without even going through a C bridge.

Mapping types

Native data types can be mapped to/from Java data types. For compound types such as objects, arrays and strings the native code must explicitly convert the data by calling methods in the JNIEnv. The following table shows the mapping of types between Java (JNI) and native code.

Native Type JNI Type Description Type signature
unsigned char jboolean unsigned 8 bits Z
signed char jbyte signed 8 bits B
unsigned short jchar unsigned 16 bits C
short jshort signed 16 bits S
long jint signed 32 bits I

long long
__int64

jlong signed 64 bits J
float jfloat 32 bits F
double jdouble 64 bits D

In addition, the signature "L fully-qualified-class ;" would mean the class uniquely specified by that name; e.g., the signature "Ljava/lang/String;" refers to the class java.lang.String. Also, prefixing [ to the signature makes the array of that type; for example, [I means the int array type. Finally, a void signature uses the V code. Here, these types are interchangeable. You can use jint where you normally use an int, and vice-versa, without any typecasting required.

However, mapping between Java Strings and arrays to native strings and arrays is different. If you use a jstring in where a char * would be, your code could crash the JVM.

JNIEXPORT void JNICALL Java_ClassName_MethodName
        (JNIEnv *env, jobject obj, jstring javaString) {
    // printf("%s", javaString);        // INCORRECT: Could crash VM!

    // Correct way: Create and release native string from Java string
    const char *nativeString = (*env)->GetStringUTFChars(env, javaString, 0);
    printf("%s", nativeString);
    (*env)->ReleaseStringUTFChars(env, javaString, nativeString);
}

The encoding used for the NewStringUTF, GetStringUTFLength, GetStringUTFChars, ReleaseStringUTFChars, GetStringUTFRegion functions is not standard UTF-8, but modified UTF-8. The null character (U+0000) and codepoints greater than or equal to U+10000 are encoded differently in modified UTF-8. Many programs actually use these functions incorrectly and treat the UTF-8 strings returned or passed into the functions as standard UTF-8 strings instead of modified UTF-8 strings. Programs should use the NewString, GetStringLength, GetStringChars, ReleaseStringChars, GetStringRegion, GetStringCritical, and ReleaseStringCritical functions, which use UTF-16LE encoding on little-endian architectures and UTF-16BE on big-endian architectures, and then use a UTF-16 to standard UTF-8 conversion routine.

The code is similar with Java arrays, as illustrated in the example below that takes the sum of all the elements in an array.

JNIEXPORT jint JNICALL Java_IntArray_sumArray
        (JNIEnv *env, jobject obj, jintArray arr) {
    jint buf[10];
    jint i, sum = 0;
    // This line is necessary, since Java arrays are not guaranteed
    // to have a continuous memory layout like C arrays.
    env->GetIntArrayRegion(arr, 0, 10, buf);
    for (i = 0; i < 10; i++) {
        sum += buf[i];
    }
    return sum;
}

Of course, there is much more to it than this.

JNIEnv*

A JNI environment pointer (JNIEnv*) is passed as an argument for each native function mapped to a Java method, allowing for interaction with the JNI environment within the native method. This JNI interface pointer can be stored, but remains valid only in the current thread. Other threads must first call AttachCurrentThread() to attach themselves to the VM and obtain a JNI interface pointer. Once attached, a native thread works like a regular Java thread running within a native method. The native thread remains attached to the VM until it calls DetachCurrentThread() to detach itself.

To attach to the current thread and get a JNI interface pointer:

JNIEnv *env;
(*g_vm)->AttachCurrentThread (g_vm, (void **) &env, NULL);

To detach from the current thread:

(*g_vm)->DetachCurrentThread (g_vm);

HelloWorld

Computer code Code listing 10.1: HelloWorld.java
 1 public class HelloWorld {
 2  private native void print();
 3 
 4  public static void main(String[] args) {
 5   new HelloWorld().print();
 6  }
 7 
 8  static {
 9   System.loadLibrary("HelloWorld");
10  }
11 }

HelloWorld.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class HelloWorld */

#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     HelloWorld
 * Method:    print
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_HelloWorld_print
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

libHelloWorld.c

 #include <stdio.h>
 #include "HelloWorld.h"

 JNIEXPORT void JNICALL
 Java_HelloWorld_print(JNIEnv *env, jobject obj)
 {
     printf("Hello World!\n");
     return;
 }

make.sh

#!/bin/sh

# openbsd 4.9
# gcc 4.2.1
# openjdk 1.7.0
JAVA_HOME=$(readlink -f /usr/bin/javac | sed "s:bin/javac::")
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
javac HelloWorld.java
javah HelloWorld
gcc -I${JAVA_HOME}/include -shared libHelloWorld.c -o libHelloWorld.so
java HelloWorld
Computer code Commands to execute on POSIX
chmod +x make.sh
./make.sh

Advanced uses

Not only can native code interface with Java, it can also draw on a Oracle wordmark.svg Java API: java.awt.Canvas, which is possible with the Java AWT Native Interface. The process is almost the same, with just a few changes. The Java AWT Native Interface is only available since J2SE 1.3.



Invoking C

You can use Runtime.exec() method to invoke a program from within a running Java application. Runtime.exec() also allows you to perform operations related to the program, such as control the program's standard input and output, wait until it completes execution, and get its exit status.

Here's a simple C application that illustrates these features. This C program will be called from Java:

#include <stdio.h>

int main() {
    printf("testing\n");
    return 0;
}

This application writes a string "testing" to standard output, and then terminates with an exit status of 0. To execute this simple program within a Java application, compile the C application:

Computer code Compilation
$ cc test.c -o test

Then invoke the C program using this Java code:

Computer code Code listing 10.2: Invoking C programs.
 1 import java.io.InputStream;
 2 import java.io.BufferedReader;
 3 import java.io.InputStreamReader;
 4 import java.io.IOException;
 5 import java.io.InterruptedException;
 6 import java.io.Process;
 7 import java.io.Runtime;
 8 
 9 import java.util.ArrayList;
10 
11 public class ExecDemo {
12     public static String[] runCommand(String cmd) throws IOException {
13         // --- set up list to capture command output lines ---
14         ArrayList list = new ArrayList();
15 
16         // --- start command running
17         Process proc = Runtime.getRuntime().exec(cmd);
18 
19         // --- get command's output stream and
20         // put a buffered reader input stream on it ---
21         InputStream istr = proc.getInputStream();
22         BufferedReader br = new BufferedReader(new InputStreamReader(istr));
23 
24         // --- read output lines from command
25         String str;
26         while ((str = br.readLine()) != null) {
27             list.add(str);
28         }
29 
30         // wait for command to terminate
31         try {
32             proc.waitFor();
33         }
34         catch (InterruptedException e) {
35             System.err.println("process was interrupted");
36         }
37 
38         // check its exit value
39         if (proc.exitValue() != 0) {
40             System.err.println("exit value was non-zero");
41         }
42 
43         // close stream
44         br.close();
45 
46         // return list of strings to caller
47         return (String[])list.toArray(new String[0]);
48     }
49 
50     public static void main(String args[]) throws IOException {
51         try {
52 
53             // run a command
54             String outlist[] = runCommand("test");
55 
56             // display its output
57             for (int i = 0; i < outlist.length; i++)
58                 System.out.println(outlist[i]);
59         }
60         catch (IOException e) {
61             System.err.println(e);
62         }
63     }
64 }

The demo calls a method runCommand to actually run the program.

Example Code section 10.1: Running a command.
1 String outlist[] = runCommand("test");

This method hooks an input stream to the program's output stream, so that it can read the program's output, and save it into a list of strings.

Example Code section 10.2: Reading the program's output.
1 InputStream istr = proc.getInputStream();
2 BufferedReader br = new BufferedReader(new InputStreamReader(istr));
3              
4 String str;
5 while ((str = br.readLine()) != null) {
6     list.add(str);
7 }

Migrating C to Java

Tools exist to aid the migration of existing projects from C to Java. In general, automated translator tools fall into one of two distinct kinds:

  • One kind converts C code to Java byte code. It is basically a compiler that creates byte code. It has the same steps as any other C compiler. See also C to Java JVM compilers.
  • The other kind translates C code to Java source code. This type is more complicated and uses various syntax rules to create readable Java source code. This option is best for those who want to move their C code to Java and stay in Java.




Byte Code

Java Byte Code is the language to which Java source is compiled and the Java Virtual Machine understands. Unlike compiled languages that have to be specifically compiled for each different type of computers, a Java program only needs to be converted to byte code once, after which it can run on any platform for which a Java Virtual Machine exists.

Bytecode is the compiled format for Java programs. Once a Java program has been converted to bytecode, it can be transferred across a network and executed by Java Virtual Machine (JVM). Bytecode files generally have a .class extension. It is not normally necessary for a Java programmer to know byte code, but it can be useful.

Other Languages

There are a number of exciting new languages being created that also compile to Java byte code, such as Groovy.

GNAT 
The GNU Ada-Compiler, is capable of compiling Ada into Java-style bytecode.
ftp://cs.nyu.edu/pub/gnat
JPython 
Compiles Python to Java-style bytecode.
http://www.jpython.org/
Kawa 
Compiles Scheme to Java-style bytecode.
http://www.gnu.org/software/kawa/


Example

Consider the following Java code.

 outer:
 for (int i = 2; i < 1000; i++) {
  for (int j = 2; j < i; j++) {
    if (i % j == 0)
      continue outer;
  }
  System.out.println (i);
 }

A Java compiler might translate the Java code above into byte code as follows, assuming the above was put in a method:

 Code:
  0:   iconst_2
  1:   istore_1
  2:   iload_1
  3:   sipush  1000
  6:   if_icmpge       44
  9:   iconst_2
  10:  istore_2
  11:  iload_2
  12:  iload_1
  13:  if_icmpge       31
  16:  iload_1
  17:  iload_2
  18:  irem             # remainder
  19:  ifne    25
  22:  goto    38
  25:  iinc    2, 1
  28:  goto    11
  31:  getstatic       #84; //Field java/lang/System.out:Ljava/io/PrintStream;
  34:  iload_1
  35:  invokevirtual   #85; //Method java/io/PrintStream.println:(I)V
  38:  iinc    1, 1
  41:  goto    2
  44:  return

Example 2

As an example we can write a simple Foo.java source:

public class Foo {
  public static void main(final String[] args) {
    System.out.println("This is a simple example of decompilation using javap");
    a();
    b();
  }
	
  public static void a() {
    System.out.println("Now we are calling a function...");
  }

  public static void b() {
    System.out.println("...and now we are calling b");
  }
}

Compile it and then move Foo.java to another directory or delete it if you wish. What can we do with javap and Foo.class ?

$javap Foo

produces this result:

Compiled from "Foo.java"
public class Foo extends java.lang.Object {
    public Foo();
    public static void main(java.lang.String[]);
    public static void a();
    public static void b();
}

As you can see the javac compiler doesn't strip any (public) variable name from the .class file. As a result the names of the functions, their parameters and types of return are exposed. (This is necessary in order for other classes to access them.)

Let's do a bit more, try:

$javap -c Foo
Compiled from "Foo.java"
public class Foo extends java.lang.Object{
public Foo();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   ldc             #3; //String This is a simple example of decompilation using javap
   5:   invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   8:   invokestatic    #5; //Method a:()V
   11:  invokestatic    #6; //Method b:()V
   14:  return

public static void a();
  Code:
   0:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   ldc             #7; //String Now we are calling a function...
   5:   invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   8:   return

public static void b();
  Code:
   0:   getstatic       #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   3:   ldc             #8; //String ...and now we are calling b
   5:   invokevirtual   #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   8:   return

}

The Java bytecodes

See Oracle's Java Virtual Machine Specification[1] for more detailed descriptions

The manipulation of the operand stack is notated as [before]→[after], where [before] is the stack before the instruction is executed and [after] is the stack after the instruction is executed. A stack with the element 'b' on the top and element 'a' just after the top element is denoted 'a,b'.

Mnemonic Opcode
(in hex)
Other bytes Stack
[before]→[after]
Description
A
aaload 32 arrayref, index → value loads onto the stack a reference from an array
aastore 53 arrayref, index, value → stores a reference into an array
aconst_null 01 → null pushes a null reference onto the stack
aload 19 index → objectref loads a reference onto the stack from a local variable #index
aload_0 2a → objectref loads a reference onto the stack from local variable 0
aload_1 2b → objectref loads a reference onto the stack from local variable 1
aload_2 2c → objectref loads a reference onto the stack from local variable 2
aload_3 2d → objectref loads a reference onto the stack from local variable 3
anewarray bd indexbyte1, indexbyte2 count → arrayref creates a new array of references of length count and component type identified by the class reference index (indexbyte1 << 8 + indexbyte2) in the constant pool
areturn b0 objectref → [empty] returns a reference from a method
arraylength be arrayref → length gets the length of an array
astore 3a index objectref → stores a reference into a local variable #index
astore_0 4b objectref → stores a reference into local variable 0
astore_1 4c objectref → stores a reference into local variable 1
astore_2 4d objectref → stores a reference into local variable 2
astore_3 4e objectref → stores a reference into local variable 3
athrow bf objectref → [empty], objectref throws an error or exception (notice that the rest of the stack is cleared, leaving only a reference to the Throwable)
B
baload 33 arrayref, index → value loads a byte or Boolean value from an array
bastore 54 arrayref, index, value → stores a byte or Boolean value into an array
bipush 10 byte → value pushes a byte onto the stack as an integer value
C
caload 34 arrayref, index → value loads a char from an array
castore 55 arrayref, index, value → stores a char into an array
checkcast c0 indexbyte1, indexbyte2 objectref → objectref checks whether an objectref is of a certain type, the class reference of which is in the constant pool at index (indexbyte1 << 8 + indexbyte2)
D
d2f 90 value → result converts a double to a float
d2i 8e value → result converts a double to an int
d2l 8f value → result converts a double to a long
dadd 63 value1, value2 → result adds two doubles
daload 31 arrayref, index → value loads a double from an array
dastore 52 arrayref, index, value → stores a double into an array
dcmpg 98 value1, value2 → result compares two doubles
dcmpl 97 value1, value2 → result compares two doubles
dconst_0 0e → 0.0 pushes the constant 0.0 onto the stack
dconst_1 0f → 1.0 pushes the constant 1.0 onto the stack
ddiv 6f value1, value2 → result divides two doubles
dload 18 index → value loads a double value from a local variable #index
dload_0 26 → value loads a double from local variable 0
dload_1 27 → value loads a double from local variable 1
dload_2 28 → value loads a double from local variable 2
dload_3 29 → value loads a double from local variable 3
dmul 6b value1, value2 → result multiplies two doubles
dneg 77 value → result negates a double
drem 73 value1, value2 → result gets the remainder from a division between two doubles
dreturn af value → [empty] returns a double from a method
dstore 39 index value → stores a double value into a local variable #index
dstore_0 47 value → stores a double into local variable 0
dstore_1 48 value → stores a double into local variable 1
dstore_2 49 value → stores a double into local variable 2
dstore_3 4a value → stores a double into local variable 3
dsub 67 value1, value2 → result subtracts a double from another
dup 59 value → value, value duplicates the value on top of the stack
dup_x1 5a value2, value1 → value1, value2, value1 inserts a copy of the top value into the stack two values from the top
dup_x2 5b value3, value2, value1 → value1, value3, value2, value1 inserts a copy of the top value into the stack two (if value2 is double or long it takes up the entry of value3, too) or three values (if value2 is neither double nor long) from the top
dup2 5c {value2, value1} → {value2, value1}, {value2, value1} duplicate top two stack words (two values, if value1 is not double nor long; a single value, if value1 is double or long)
dup2_x1 5d value3, {value2, value1} → {value2, value1}, value3, {value2, value1} duplicate two words and insert beneath third word (see explanation above)
dup2_x2 5e {value4, value3}, {value2, value1} → {value2, value1}, {value4, value3}, {value2, value1} duplicate two words and insert beneath fourth word
F
f2d 8d value → result converts a float to a double
f2i 8b value → result converts a float to an int
f2l 8c value → result converts a float to a long
fadd 62 value1, value2 → result adds two floats
faload 30 arrayref, index → value loads a float from an array
fastore 51 arreyref, index, value → stores a float in an array
fcmpg 96 value1, value2 → result compares two floats
fcmpl 95 value1, value2 → result compares two floats
fconst_0 0b → 0.0f pushes 0.0f on the stack
fconst_1 0c → 1.0f pushes 1.0f on the stack
fconst_2 0d → 2.0f pushes 2.0f on the stack
fdiv 6e value1, value2 → result divides two floats
fload 17 index → value loads a float value from a local variable #index
fload_0 22 → value loads a float value from local variable 0
fload_1 23 → value loads a float value from local variable 1
fload_2 24 → value loads a float value from local variable 2
fload_3 25 → value loads a float value from local variable 3
fmul 6a value1, value2 → result multiplies two floats
fneg 76 value → result negates a float
frem 72 value1, value2 → result gets the remainder from a division between two floats
freturn ae value → [empty] returns a float from method
fstore 38 index value → stores a float value into a local variable #index
fstore_0 43 value → stores a float value into local variable 0
fstore_1 44 value → stores a float value into local variable 1
fstore_2 45 value → stores a float value into local variable 2
fstore_3 46 value → stores a float value into local variable 3
fsub 66 value1, value2 → result subtracts two floats
G
getfield b4 index1, index2 objectref → value gets a field value of an object objectref, where the field is identified by field reference in the constant pool index (index1 << 8 + index2)
getstatic b2 index1, index2 → value gets a static field value of a class, where the field is identified by field reference in the constant pool index (index1 << 8 + index2)
goto a7 branchbyte1, branchbyte2 [no change] goes to another instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2)
goto_w c8 branchbyte1, branchbyte2, branchbyte3, branchbyte4 [no change] goes to another instruction at branchoffset (signed int constructed from unsigned bytes branchbyte1 << 24 + branchbyte2 << 16 + branchbyte3 << 8 + branchbyte4)
I
i2b 91 value → result converts an int into a byte
i2c 92 value → result converts an int into a character
i2d 87 value → result converts an int into a double
i2f 86 value → result converts an int into a float
i2l 85 value → result converts an int into a long
i2s 93 value → result converts an int into a short
iadd 60 value1, value2 → result adds two ints together
iaload 2e arrayref, index → value loads an int from an array
iand 7e value1, value2 → result performs a logical and on two integers
iastore 4f arrayref, index, value → stores an int into an array
iconst_m1 02 → -1 loads the int value -1 onto the stack
iconst_0 03 → 0 loads the int value 0 onto the stack
iconst_1 04 → 1 loads the int value 1 onto the stack
iconst_2 05 → 2 loads the int value 2 onto the stack
iconst_3 06 → 3 loads the int value 3 onto the stack
iconst_4 07 → 4 loads the int value 4 onto the stack
iconst_5 08 → 5 loads the int value 5 onto the stack
idiv 6c value1, value2 → result divides two integers
if_acmpeq a5 branchbyte1, branchbyte2 value1, value2 → if references are equal, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2)
if_acmpne a6 branchbyte1, branchbyte2 value1, value2 → if references are not equal, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2)
if_icmpeq 9f branchbyte1, branchbyte2 value1, value2 → if ints are equal, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2)
if_icmpne a0 branchbyte1, branchbyte2 value1, value2 → if ints are not equal, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2)
if_icmplt a1 branchbyte1, branchbyte2 value1, value2 → if value1 is less than value2, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2)
if_icmpge a2 branchbyte1, branchbyte2 value1, value2 → if value1 is greater than or equal to value2, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2)
if_icmpgt a3 branchbyte1, branchbyte2 value1, value2 → if value1 is greater than value2, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2)
if_icmple a4 branchbyte1, branchbyte2 value1, value2 → if value1 is less than or equal to value2, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2)
ifeq 99 branchbyte1, branchbyte2 value → if value is 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2)
ifne 9a branchbyte1, branchbyte2 value → if value is not 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2)
iflt 9b branchbyte1, branchbyte2 value → if value is less than 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2)
ifge 9c branchbyte1, branchbyte2 value → if value is greater than or equal to 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2)
ifgt 9d branchbyte1, branchbyte2 value → if value is greater than 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2)
ifle 9e branchbyte1, branchbyte2 value → if value is less than or equal to 0, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2)
ifnonnull c7 branchbyte1, branchbyte2 value → if value is not null, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2)
ifnull c6 branchbyte1, branchbyte2 value → if value is null, branch to instruction at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2)
iinc 84 index, const [No change] increment local variable #index by signed byte const
iload 15 index → value loads an int value from a variable #index
iload_0 1a → value loads an int value from variable 0
iload_1 1b → value loads an int value from variable 1
iload_2 1c → value loads an int value from variable 2
iload_3 1d → value loads an int value from variable 3
imul 68 value1, value2 → result multiply two integers
ineg 74 value → result negate int
instanceof c1 indexbyte1, indexbyte2 objectref → result determines if an object objectref is of a given type, identified by class reference index in constant pool (indexbyte1 << 8 + indexbyte2)
invokeinterface b9 indexbyte1, indexbyte2, count, 0 objectref, [arg1, arg2, ...] → invokes an interface method on object objectref, where the interface method is identified by method reference index in constant pool (indexbyte1 << 8 + indexbyte2) and count is the number of arguments to pop from the stack frame including the object on which the method is being called and must always be greater than or equal to 1
invokespecial b7 indexbyte1, indexbyte2 objectref, [arg1, arg2, ...] → invoke instance method on object objectref requiring special handling (instance initialization method, a private method, or a superclass method), where the method is identified by method reference index in constant pool (indexbyte1 << 8 + indexbyte2)
invokestatic b8 indexbyte1, indexbyte2 [arg1, arg2, ...] → invoke a static method, where the method is identified by method reference index in constant pool (indexbyte1 << 8 + indexbyte2)
invokevirtual b6 indexbyte1, indexbyte2 objectref, [arg1, arg2, ...] → invoke virtual method on object objectref, where the method is identified by method reference index in constant pool (indexbyte1 << 8 + indexbyte2)
ior 80 value1, value2 → result logical int or
irem 70 value1, value2 → result logical int remainder
ireturn ac value → [empty] returns an integer from a method
ishl 78 value1, value2 → result int shift left
ishr 7a value1, value2 → result int shift right
istore 36 index value → store int value into variable #index
istore_0 3b value → store int value into variable 0
istore_1 3c value → store int value into variable 1
istore_2 3d value → store int value into variable 2
istore_3 3e value → store int value into variable 3
isub 64 value1, value2 → result int subtract
iushr 7c value1, value2 → result int shift right
ixor 82 value1, value2 → result int xor
J
jsr a8 branchbyte1, branchbyte2 → address jump to subroutine at branchoffset (signed short constructed from unsigned bytes branchbyte1 << 8 + branchbyte2) and place the return address on the stack
jsr_w c9 branchbyte1, branchbyte2, branchbyte3, branchbyte4 → address jump to subroutine at branchoffset (signed int constructed from unsigned bytes branchbyte1 << 24 + branchbyte2 << 16 + branchbyte3 << 8 + branchbyte4) and place the return address on the stack
L
l2d 8a value → result converts a long to a double
l2f 89 value → result converts a long to a float
l2i 88 value → result converts a long to an int
ladd 61 value1, value2 → result add two longs
laload 2f arrayref, index → value load a long from an array
land 7f value1, value2 → result bitwise and of two longs
lastore 50 arrayref, index, value → store a long to an array
lcmp 94 value1, value2 → result compares two longs values
lconst_0 09 → 0L pushes the long 0 onto the stack
lconst_1 0a → 1L pushes the long 1 onto the stack
ldc 12 index → value pushes a constant #index from a constant pool (String, int, float or class type) onto the stack
ldc_w 13 indexbyte1, indexbyte2 → value pushes a constant #index from a constant pool (String, int, float or class type) onto the stack (wide index is constructed as indexbyte1 << 8 + indexbyte2)
ldc2_w 14 indexbyte1, indexbyte2 → value pushes a constant #index from a constant pool (double or long) onto the stack (wide index is constructed as indexbyte1 << 8 + indexbyte2)
ldiv 6d value1, value2 → result divide two longs
lload 16 index → value load a long value from a local variable #index
lload_0 1e → value load a long value from a local variable 0
lload_1 1f → value load a long value from a local variable 1
lload_2 20 → value load a long value from a local variable 2
lload_3 21 → value load a long value from a local variable 3
lmul 69 value1, value2 → result multiplies two longs
lneg 75 value → result negates a long
lookupswitch ab <0-3 bytes padding>, defaultbyte1, defaultbyte2, defaultbyte3, defaultbyte4, npairs1, npairs2, npairs3, npairs4, match-offset pairs... key → a target address is looked up from a table using a key and execution continues from the instruction at that address
lor 81 value1, value2 → result bitwise or of two longs
lrem 71 value1, value2 → result remainder of division of two longs
lreturn ad value → [empty] returns a long value
lshl 79 value1, value2 → result bitwise shift left of a long value1 by value2 positions
lshr 7b value1, value2 → result bitwise shift right of a long value1 by value2 positions
lstore 37 index value → store a long value in a local variable #index
lstore_0 3f value → store a long value in a local variable 0
lstore_1 40 value → store a long value in a local variable 1
lstore_2 41 value → store a long value in a local variable 2
lstore_3 42 value → store a long value in a local variable 3
lsub 65 value1, value2 → result subtract two longs
lushr 7d value1, value2 → result bitwise shift right of a long value1 by value2 positions, unsigned
lxor 83 value1, value2 → result bitwise exclusive or of two longs
M
monitorenter c2 objectref → enter monitor for object ("grab the lock" - start of synchronized() section)
monitorexit c3 objectref → exit monitor for object ("release the lock" - end of synchronized() section)
multianewarray c5 indexbyte1, indexbyte2, dimensions count1, [count2,...] → arrayref create a new array of dimensions dimensions with elements of type identified by class reference in constant pool index (indexbyte1 << 8 + indexbyte2); the sizes of each dimension is identified by count1, [count2, etc]
N
new bb indexbyte1, indexbyte2 → objectref creates new object of type identified by class reference in constant pool index (indexbyte1 << 8 + indexbyte2)
newarray bc atype count → arrayref creates new array with count elements of primitive type identified by atype
nop 00 [No change] performs no operation
P
pop 57 value → discards the top value on the stack
pop2 58 {value2, value1} → discards the top two values on the stack (or one value, if it is a double or long)
putfield b5 indexbyte1, indexbyte2 objectref, value → set field to value in an object objectref, where the field is identified by a field reference index in constant pool (indexbyte1 << 8 + indexbyte2)
putstatic b3 indexbyte1, indexbyte2 value → set static field to value in a class, where the field is identified by a field reference index in constant pool (indexbyte1 << 8 + indexbyte2)
R
ret a9 index [No change] continue execution from address taken from a local variable #index (the asymmetry with jsr is intentional)
return b1 → [empty] return void from method
S
saload 35 arrayref, index → value load short from array
sastore 56 arrayref, index, value → store short to array
sipush 11 byte1, byte2 → value pushes a signed integer (byte1 << 8 + byte2) onto the stack
swap 5f value2, value1 → value1, value2 swaps two top words on the stack (note that value1 and value2 must not be double or long)
T
tableswitch aa [0-3 bytes padding], defaultbyte1, defaultbyte2, defaultbyte3, defaultbyte4, lowbyte1, lowbyte2, lowbyte3, lowbyte4, highbyte1, highbyte2, highbyte3, highbyte4, jump offsets... index → continue execution from an address in the table at offset index
W
wide c4 opcode, indexbyte1, indexbyte2
or
iinc, indexbyte1, indexbyte2, countbyte1, countbyte2
[same as for corresponding instructions] execute opcode, where opcode is either iload, fload, aload, lload, dload, istore, fstore, astore, lstore, dstore, or ret, but assume the index is 16 bit; or execute iinc, where the index is 16 bits and the constant to increment by is a signed 16 bit short
Unused
breakpoint ca reserved for breakpoints in Java debuggers; should not appear in any class file
impdep1 fe reserved for implementation-dependent operations within debuggers; should not appear in any class file
impdep2 ff reserved for implementation-dependent operations within debuggers; should not appear in any class file
(no name) cb-fd these values are currently unassigned for opcodes and are reserved for future use
xxxunusedxxx ba this opcode is reserved "for historical reasons"

References

  1. Oracle's Java Virtual Machine Specification

External Links



Appendices

Links

External References

External links

Newsgroups:


Glossary

This is a glossary of the book.

Contents: Top - 0–9 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

A

annotation 
A means of attaching metadata to methods and classes directly in the source code.

B

byte code 
Code interpreted by the Java virtual machine; the target code of Java compilation.

G

generics 
A means of passing a data type as an argument of another type, such as Vector<JButton>;

P

primitive type 
One of the types that do not require allocation on stack, such as int, byte, or long.

R

reflection 
A way of treating classes and methods as objects on their own, to be referred to during runtime, for instance by quering a particular class about its methods and their parameters.



Index

This is an alphabetical index to the book about basic java.

Contents: Top - 0–9 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z


GNU Free Documentation License

Version 1.3, 3 November 2008 Copyright (C) 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. <http://fsf.org/>

Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.

0. PREAMBLE

The purpose of this License is to make a manual, textbook, or other functional and useful document "free" in the sense of freedom: to assure everyone the effective freedom to copy and redistribute it, with or without modifying it, either commercially or noncommercially. Secondarily, this License preserves for the author and publisher a way to get credit for their work, while not being considered responsible for modifications made by others.

This License is a kind of "copyleft", which means that derivative works of the document must themselves be free in the same sense. It complements the GNU General Public License, which is a copyleft license designed for free software.

We have designed this License in order to use it for manuals for free software, because free software needs free documentation: a free program should come with manuals providing the same freedoms that the software does. But this License is not limited to software manuals; it can be used for any textual work, regardless of subject matter or whether it is published as a printed book. We recommend this License principally for works whose purpose is instruction or reference.

1. APPLICABILITY AND DEFINITIONS

This License applies to any manual or other work, in any medium, that contains a notice placed by the copyright holder saying it can be distributed under the terms of this License. Such a notice grants a world-wide, royalty-free license, unlimited in duration, to use that work under the conditions stated herein. The "Document", below, refers to any such manual or work. Any member of the public is a licensee, and is addressed as "you". You accept the license if you copy, modify or distribute the work in a way requiring permission under copyright law.

A "Modified Version" of the Document means any work containing the Document or a portion of it, either copied verbatim, or with modifications and/or translated into another language.

A "Secondary Section" is a named appendix or a front-matter section of the Document that deals exclusively with the relationship of the publishers or authors of the Document to the Document's overall subject (or to related matters) and contains nothing that could fall directly within that overall subject. (Thus, if the Document is in part a textbook of mathematics, a Secondary Section may not explain any mathematics.) The relationship could be a matter of historical connection with the subject or with related matters, or of legal, commercial, philosophical, ethical or political position regarding them.

The "Invariant Sections" are certain Secondary Sections whose titles are designated, as being those of Invariant Sections, in the notice that says that the Document is released under this License. If a section does not fit the above definition of Secondary then it is not allowed to be designated as Invariant. The Document may contain zero Invariant Sections. If the Document does not identify any Invariant Sections then there are none.

The "Cover Texts" are certain short passages of text that are listed, as Front-Cover Texts or Back-Cover Texts, in the notice that says that the Document is released under this License. A Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at most 25 words.

A "Transparent" copy of the Document means a machine-readable copy, represented in a format whose specification is available to the general public, that is suitable for revising the document straightforwardly with generic text editors or (for images composed of pixels) generic paint programs or (for drawings) some widely available drawing editor, and that is suitable for input to text formatters or for automatic translation to a variety of formats suitable for input to text formatters. A copy made in an otherwise Transparent file format whose markup, or absence of markup, has been arranged to thwart or discourage subsequent modification by readers is not Transparent. An image format is not Transparent if used for any substantial amount of text. A copy that is not "Transparent" is called "Opaque".

Examples of suitable formats for Transparent copies include plain ASCII without markup, Texinfo input format, LaTeX input format, SGML or XML using a publicly available DTD, and standard-conforming simple HTML, PostScript or PDF designed for human modification. Examples of transparent image formats include PNG, XCF and JPG. Opaque formats include proprietary formats that can be read and edited only by proprietary word processors, SGML or XML for which the DTD and/or processing tools are not generally available, and the machine-generated HTML, PostScript or PDF produced by some word processors for output purposes only.

The "Title Page" means, for a printed book, the title page itself, plus such following pages as are needed to hold, legibly, the material this License requires to appear in the title page. For works in formats which do not have any title page as such, "Title Page" means the text near the most prominent appearance of the work's title, preceding the beginning of the body of the text.

The "publisher" means any person or entity that distributes copies of the Document to the public.

A section "Entitled XYZ" means a named subunit of the Document whose title either is precisely XYZ or contains XYZ in parentheses following text that translates XYZ in another language. (Here XYZ stands for a specific section name mentioned below, such as "Acknowledgements", "Dedications", "Endorsements", or "History".) To "Preserve the Title" of such a section when you modify the Document means that it remains a section "Entitled XYZ" according to this definition.

The Document may include Warranty Disclaimers next to the notice which states that this License applies to the Document. These Warranty Disclaimers are considered to be included by reference in this License, but only as regards disclaiming warranties: any other implication that these Warranty Disclaimers may have is void and has no effect on the meaning of this License.

2. VERBATIM COPYING

You may copy and distribute the Document in any medium, either commercially or noncommercially, provided that this License, the copyright notices, and the license notice saying this License applies to the Document are reproduced in all copies, and that you add no other conditions whatsoever to those of this License. You may not use technical measures to obstruct or control the reading or further copying of the copies you make or distribute. However, you may accept compensation in exchange for copies. If you distribute a large enough number of copies you must also follow the conditions in section 3.

You may also lend copies, under the same conditions stated above, and you may publicly display copies.

3. COPYING IN QUANTITY

If you publish printed copies (or copies in media that commonly have printed covers) of the Document, numbering more than 100, and the Document's license notice requires Cover Texts, you must enclose the copies in covers that carry, clearly and legibly, all these Cover Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on the back cover. Both covers must also clearly and legibly identify you as the publisher of these copies. The front cover must present the full title with all words of the title equally prominent and visible. You may add other material on the covers in addition. Copying with changes limited to the covers, as long as they preserve the title of the Document and satisfy these conditions, can be treated as verbatim copying in other respects.

If the required texts for either cover are too voluminous to fit legibly, you should put the first ones listed (as many as fit reasonably) on the actual cover, and continue the rest onto adjacent pages.

If you publish or distribute Opaque copies of the Document numbering more than 100, you must either include a machine-readable Transparent copy along with each Opaque copy, or state in or with each Opaque copy a computer-network location from which the general network-using public has access to download using public-standard network protocols a complete Transparent copy of the Document, free of added material. If you use the latter option, you must take reasonably prudent steps, when you begin distribution of Opaque copies in quantity, to ensure that this Transparent copy will remain thus accessible at the stated location until at least one year after the last time you distribute an Opaque copy (directly or through your agents or retailers) of that edition to the public.

It is requested, but not required, that you contact the authors of the Document well before redistributing any large number of copies, to give them a chance to provide you with an updated version of the Document.

4. MODIFICATIONS

You may copy and distribute a Modified Version of the Document under the conditions of sections 2 and 3 above, provided that you release the Modified Version under precisely this License, with the Modified Version filling the role of the Document, thus licensing distribution and modification of the Modified Version to whoever possesses a copy of it. In addition, you must do these things in the Modified Version:

  1. Use in the Title Page (and on the covers, if any) a title distinct from that of the Document, and from those of previous versions (which should, if there were any, be listed in the History section of the Document). You may use the same title as a previous version if the original publisher of that version gives permission.
  2. List on the Title Page, as authors, one or more persons or entities responsible for authorship of the modifications in the Modified Version, together with at least five of the principal authors of the Document (all of its principal authors, if it has fewer than five), unless they release you from this requirement.
  3. State on the Title page the name of the publisher of the Modified Version, as the publisher.
  4. Preserve all the copyright notices of the Document.
  5. Add an appropriate copyright notice for your modifications adjacent to the other copyright notices.
  6. Include, immediately after the copyright notices, a license notice giving the public permission to use the Modified Version under the terms of this License, in the form shown in the Addendum below.
  7. Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice.
  8. Include an unaltered copy of this License.
  9. Preserve the section Entitled "History", Preserve its Title, and add to it an item stating at least the title, year, new authors, and publisher of the Modified Version as given on the Title Page. If there is no section Entitled "History" in the Document, create one stating the title, year, authors, and publisher of the Document as given on its Title Page, then add an item describing the Modified Version as stated in the previous sentence.
  10. Preserve the network location, if any, given in the Document for public access to a Transparent copy of the Document, and likewise the network locations given in the Document for previous versions it was based on. These may be placed in the "History" section. You may omit a network location for a work that was published at least four years before the Document itself, or if the original publisher of the version it refers to gives permission.
  11. For any section Entitled "Acknowledgements" or "Dedications", Preserve the Title of the section, and preserve in the section all the substance and tone of each of the contributor acknowledgements and/or dedications given therein.
  12. Preserve all the Invariant Sections of the Document, unaltered in their text and in their titles. Section numbers or the equivalent are not considered part of the section titles.
  13. Delete any section Entitled "Endorsements". Such a section may not be included in the Modified version.
  14. Do not retitle any existing section to be Entitled "Endorsements" or to conflict in title with any Invariant Section.
  15. Preserve any Warranty Disclaimers.

If the Modified Version includes new front-matter sections or appendices that qualify as Secondary Sections and contain no material copied from the Document, you may at your option designate some or all of these sections as invariant. To do this, add their titles to the list of Invariant Sections in the Modified Version's license notice. These titles must be distinct from any other section titles.

You may add a section Entitled "Endorsements", provided it contains nothing but endorsements of your Modified Version by various parties—for example, statements of peer review or that the text has been approved by an organization as the authoritative definition of a standard.

You may add a passage of up to five words as a Front-Cover Text, and a passage of up to 25 words as a Back-Cover Text, to the end of the list of Cover Texts in the Modified Version. Only one passage of Front-Cover Text and one of Back-Cover Text may be added by (or through arrangements made by) any one entity. If the Document already includes a cover text for the same cover, previously added by you or by arrangement made by the same entity you are acting on behalf of, you may not add another; but you may replace the old one, on explicit permission from the previous publisher that added the old one.

The author(s) and publisher(s) of the Document do not by this License give permission to use their names for publicity for or to assert or imply endorsement of any Modified Version.

5. COMBINING DOCUMENTS

You may combine the Document with other documents released under this License, under the terms defined in section 4 above for modified versions, provided that you include in the combination all of the Invariant Sections of all of the original documents, unmodified, and list them all as Invariant Sections of your combined work in its license notice, and that you preserve all their Warranty Disclaimers.

The combined work need only contain one copy of this License, and multiple identical Invariant Sections may be replaced with a single copy. If there are multiple Invariant Sections with the same name but different contents, make the title of each such section unique by adding at the end of it, in parentheses, the name of the original author or publisher of that section if known, or else a unique number. Make the same adjustment to the section titles in the list of Invariant Sections in the license notice of the combined work.

In the combination, you must combine any sections Entitled "History" in the various original documents, forming one section Entitled "History"; likewise combine any sections Entitled "Acknowledgements", and any sections Entitled "Dedications". You must delete all sections Entitled "Endorsements".

6. COLLECTIONS OF DOCUMENTS

You may make a collection consisting of the Document and other documents released under this License, and replace the individual copies of this License in the various documents with a single copy that is included in the collection, provided that you follow the rules of this License for verbatim copying of each of the documents in all other respects.

You may extract a single document from such a collection, and distribute it individually under this License, provided you insert a copy of this License into the extracted document, and follow this License in all other respects regarding verbatim copying of that document.

7. AGGREGATION WITH INDEPENDENT WORKS

A compilation of the Document or its derivatives with other separate and independent documents or works, in or on a volume of a storage or distribution medium, is called an "aggregate" if the copyright resulting from the compilation is not used to limit the legal rights of the compilation's users beyond what the individual works permit. When the Document is included in an aggregate, this License does not apply to the other works in the aggregate which are not themselves derivative works of the Document.

If the Cover Text requirement of section 3 is applicable to these copies of the Document, then if the Document is less than one half of the entire aggregate, the Document's Cover Texts may be placed on covers that bracket the Document within the aggregate, or the electronic equivalent of covers if the Document is in electronic form. Otherwise they must appear on printed covers that bracket the whole aggregate.

8. TRANSLATION

Translation is considered a kind of modification, so you may distribute translations of the Document under the terms of section 4. Replacing Invariant Sections with translations requires special permission from their copyright holders, but you may include translations of some or all Invariant Sections in addition to the original versions of these Invariant Sections. You may include a translation of this License, and all the license notices in the Document, and any Warranty Disclaimers, provided that you also include the original English version of this License and the original versions of those notices and disclaimers. In case of a disagreement between the translation and the original version of this License or a notice or disclaimer, the original version will prevail.

If a section in the Document is Entitled "Acknowledgements", "Dedications", or "History", the requirement (section 4) to Preserve its Title (section 1) will typically require changing the actual title.

9. TERMINATION

You may not copy, modify, sublicense, or distribute the Document except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, or distribute it is void, and will automatically terminate your rights under this License.

However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation.

Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice.

Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, receipt of a copy of some or all of the same material does not give you any rights to use it.

10. FUTURE REVISIONS OF THIS LICENSE

The Free Software Foundation may publish new, revised versions of the GNU Free Documentation License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. See http://www.gnu.org/copyleft/.

Each version of the License is given a distinguishing version number. If the Document specifies that a particular numbered version of this License "or any later version" applies to it, you have the option of following the terms and conditions either of that specified version or of any later version that has been published (not as a draft) by the Free Software Foundation. If the Document does not specify a version number of this License, you may choose any version ever published (not as a draft) by the Free Software Foundation. If the Document specifies that a proxy can decide which future versions of this License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Document.

11. RELICENSING

"Massive Multiauthor Collaboration Site" (or "MMC Site") means any World Wide Web server that publishes copyrightable works and also provides prominent facilities for anybody to edit those works. A public wiki that anybody can edit is an example of such a server. A "Massive Multiauthor Collaboration" (or "MMC") contained in the site means any set of copyrightable works thus published on the MMC site.

"CC-BY-SA" means the Creative Commons Attribution-Share Alike 3.0 license published by Creative Commons Corporation, a not-for-profit corporation with a principal place of business in San Francisco, California, as well as future copyleft versions of that license published by that same organization.

"Incorporate" means to publish or republish a Document, in whole or in part, as part of another Document.

An MMC is "eligible for relicensing" if it is licensed under this License, and if all works that were first published under this License somewhere other than this MMC, and subsequently incorporated in whole or in part into the MMC, (1) had no cover texts or invariant sections, and (2) were thus incorporated prior to November 1, 2008.

The operator of an MMC Site may republish an MMC contained in the site under CC-BY-SA on the same site at any time before August 1, 2009, provided the MMC is eligible for relicensing.

How to use this License for your documents

To use this License in a document you have written, include a copy of the License in the document and put the following copyright and license notices just after the title page:

Copyright (c) YEAR YOUR NAME.
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
A copy of the license is included in the section entitled "GNU
Free Documentation License".

If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, replace the "with...Texts." line with this:

with the Invariant Sections being LIST THEIR TITLES, with the
Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.

If you have Invariant Sections without Cover Texts, or some other combination of the three, merge those two alternatives to suit the situation.

If your document contains nontrivial examples of program code, we recommend releasing these examples in parallel under your choice of free software license, such as the GNU General Public License, to permit their use in free software.