Java Programming/Print version2
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)
|
|
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:
|
|
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:
|
|
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:
Code section 5.1: Collection feeding.
Collection ageList = new ArrayList();
ageList.add(new Integer(46));
ageList.add("50");
|
|
|
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.
Code section 5.3: Collection with generics.
Collection<Integer> ageList = new ArrayList<Integer>();
ageList.add(new Integer(46)); // Integer can be added
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.
Code section 5.4: Item reading.
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. |
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.util.HashSet<E>
- This is the basic implementation of the
Set
interface. Not synchronized. Allows thenull
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. Theequals()
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()
andhashCode()
methods in the Apple and Orange classes - Create
appleEquals()
method in the Apple class, and createorangeEquals()
method in the Orange class - Override the
hashCode()
method in the Fruit class and return the same value, so theequals()
is called by the Set implementation - Override the
equals()
method in the Fruit class for something like this.
- Do not override the
Code section 5.5: equals method implementation.
public boolean equals(Object obj) {
boolean ret = false;
if (this instanceof Apple &&
obj instanceof Apple) {
ret = this.appleEquals(obj);
} else if (this instanceof Orange &&
obj instanceof Orange) {
ret = this.orangeEquals(obj);
} else {
// Can not compare Orange to Apple
ret = false;
}
return ret;
}
|
Note:
- Only the objects that have the same hashCode will be compared.
- You are responsible to override the
equals()
andhashCode()
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 defaulthashCode()
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 theequals()
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.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 theArrayList
. 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 theLinkedList
. - 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.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. |
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(
|
|
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
.
Code section 5.6: Collection transfer.
import java.util.Collection
import java.util.Iterator
...
public boolean addAll(Collection coll) {
int sizeBefore = this.size();
Iterator iter = coll.iterator();
while(iter.hasNext()) {
this.add(iter.next());
}
if (sizeBefore > this.size()) {
return true;
} else {
return false;
}
}
|
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:
Code section 5.7: Iteration on a collection.
import java.util.Collection
import java.util.Iterator
import java.yourcompany.Customer
...
public String printCustomerNames(Collection customerColl) {
StringBuffer buf = new StringBuffer();
Iterator iter = customerColl.iterator();
while(iter.hasNext()) {
Customer cust = (Customer) iter.next();
buf.append(cust.getName());
buf.append( "\n" );
}
return buf.toString();
}
|
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 in the list. The existing element at the position and all the elements below it are shifted (this is the difference from the
set
method with the same parameters). ThrowsIndexOutOfBoundsException
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 <String> al= new ArrayList <String>();
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
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 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
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 |
Question: Consider the following 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?
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.
Code section 5.17: Use of a map.
import java.util.Map;
import java.util.Hashtable;
...
Map map = new Hashtable();
...
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.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:
|
|
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:
|
|
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.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 onlyif (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.
Code section 5.19: Reference equality.
if (objRef1 == objRef2) {
// The two object references point to the same object
}
|
Comparing for value equality
To be able to compare two Java objects of the same class the
method must be overridden and implemented by the class.
boolean
equals(Object
obj)
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
.
Code listing 5.5: Customer.java
public class Customer {
private String name;
private String address;
private String description;
// ...
public boolean equals(Object obj) {
if (this == obj) {
return true;
} else if (obj == null) {
return false;
} else if (obj instanceof Customer cust) {
if ( ((cust.getName() == null && name == null) || cust.getName().equals(name))
&& ((cust.getAddress() == null && address == null) || cust.getAddress().equals(address))
) {
return true;
}
}
return false;
}
}
|
After the equals()
method is overriden, two objects from the same class can be compared like this:
Code section 5.20: Method usage.
Customer cust1 = new Customer();
Customer cust2 = new Customer();
//...
if (cust1.equals(cust2)) {
// Two Customers are equal, by name and address
}
|
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.
Code listing 5.6: SortableCustomer.java
public class SortableCustomer implements Comparable<SortableCustomer> {
private String name;
private String address;
private String description;
// ...
public int compareTo(SortableCustomer anotherCustomer) {
if (name.compareTo(anotherCustomer.getName()) == 0) {
return address.compareTo(anotherCustomer.getAddress());
} else {
return name.compareTo(anotherCustomer.getName());
}
}
}
|
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.
Code listing 5.7: CustomerComparator.java
public class CustomerComparator implements Comparator<Customer> {
public int compare(Customer cust1, Customer cust2) {
return cust1.getName().compareTo(cust2.getName());
}
}
|
The above class then can be associated with a SortedSet or other collections that support sorting.
Code section 5.21: Comparator usage.
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.
Code section 5.22: Customized comparison.
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
.
Code section 5.23: Array sorting.
SortableCustomer[] customerArray;
//...
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 you 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 matchingcatch
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 thecatch
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 thejava.lang.Throwable
. See the UML diagram below.
Figure 6.1: Java exception classes
|
- 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. The name of the exception should be meaningful, and should represent the problem. For example,
CustomerNotFoundException
may indicate that a 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.
|
|
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:
|
|
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:
- The default constructor; and,
- A constructor taking a string argument so that you can place pertinent information in the exception.
Code section 6.1: Instance of an exception object with the default constructor.
new Exception();
|
Code section 6.2: Instance of an Exception object by passing string in constructor.
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
|
Figure 6.2: The exception classes and their inheritance model in the JCL. |
try
/catch
statement
Try/Catch is straight up better.
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:
Code section 6.3: Division into a try block.
int a = 4;
int b = 2;
int result = 0;
try {
int c = a / b;
result = c;
} catch(ArithmeticException ex) {
result = 0;
}
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.
Code section 6.4: Catching 'division by zero' errors.
int a = 4;
int b = 0;
int result = 0;
try {
int c = a / b;
result = c;
} catch(ArithmeticException ex) {
result = 0;
}
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:
Code section 6.5: Uncaught exception.
int a = 4;
int b = 0;
int result = 0;
try {
int c = a / b;
result = c;
} catch(NullPointerException ex) {
result = 0;
}
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.
|
|
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:
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:
Code section 6.8: Catching and throwing exceptions.
public void methodC() throws CustomException, SomeException {
try {
methodB();
} catch(AnotherException e) {
// Handle caught exceptions.
}
methodA();
}
|
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 a checked exception is, consider the following code:
Code section 6.9: Unhandled exception.
public void ioOperation(boolean isResourceAvailable) {
if (!isResourceAvailable) {
throw new IOException();
}
}
|
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.
|
|
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?
JAVA 1.8 onwards: When interfaces are involved, the implementation declaration may skip a throws-clause but if one wish to have then should be compatible with the interface declarations. In other words, the implementation should throw the declared exception or it's sub-type or no exception.
Prior to Java 1.8: The implementer must declare same exception or its subclass.
Unchecked Exceptions
Unchecked, uncaught or runtime exceptions are exceptions that can be thrown without being caught or declared:
Code section 6.12: Throwing an exception without declaring it or catching it.
public void futureMethod() {
throw new RuntimeException("This method is not yet implemented");
}
|
...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.
Code section 6.13: Logging an exception.
public long getLastModified(HttpServletRequest req) {
try {
...
return getTimeStamp();
...
} catch(RuntimeException e) {
log.error("Error during handling post request", e);
throw e;
}
}
|
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
can be assigned to an object reference.
NullPointerException
is thrown when an application attempts to use an object reference, having 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.
Code section 6.13: Null pointer.
Object obj = null;
obj.toString(); // This statement will throw a NullPointerException
|
The above code shows one of the pitfall 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.
Code section 6.14: Non-instantiated declared object.
public Person getPerson(boolean isWoman) {
Person person = null;
if (isWoman) {
person = createWoman();
} else {
person = createMan();
}
return person;
}
|
In the 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
. It does not describe general techniques for how you should program Java. It is of some use, 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 NullPointerException
s. 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 NullPointerException
s first, and become competent with that. These suggestions will help you to cause less NullPointerException
s, but they don't replace the need to know about NullPointerException
s.
Comparing string variable with a string literal
When you compare a variable with a string literal, most of people would do that this way:
Code section 6.15: Bad comparison.
if (state.equals("OK")) {
...
}
|
Always put the string literal first:
Code section 6.16: Better comparison.
if ("OK".equals(state)) {
...
}
|
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:
Code section 6.17: Declaring an exception.
String s = null;
while (something) {
if (something2) {
s = "yep";
}
}
if (s != null) {
something3(s);
}
|
You can replace this with:
Code section 6.18: Declaring an exception.
boolean done = false;
while (!done && something) {
if (something2) {
done = true;
something3("yep");
}
}
|
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:
Code section 6.19: Declaring an exception.
Object[] objects = {"blah", 5, new File("/usr/bin")};
|
or:
Code section 6.20: Declaring an exception.
Object[] objects;
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:
Code section 6.21: Declaring an exception.
File file = new File("/etc");
File[] files = file.listFiles();
if (files != null) {
stuff
}
|
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.
Code section 6.22: Visit a collection.
Collection<Integer> myNumbers = buildNumbers();
for (Integer myNumber : myNumbers) {
System.out.println(myNumber);
}
|
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:
Code section 6.23: Visit a collection safety.
Collection<Integer> myNumbers = buildNumbers();
if (myNumbers != null) {
for (Integer myNumber : myNumbers) {
System.out.println(myNumber);
}
}
|
External tools
There is tools like FindBugs that parse your code and warn you about potential bugs. Most of the time, it detects possible null pointers.
Stack trace
A Stack Trace is a list of method calls from the point when the application was started to the current location of execution within the program. A Stack Trace is produced automatically by the Java Virtual Machine when an exception is thrown to indicate the location and progression of the program up to the point of the exception. The most recent method calls are at the top of the list.
|
|
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:
Code section 6.24: Stack frame.
public StackTraceElement(String declaringClass,
String methodName,
String fileName,
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:
Code section 6.25: Save the stack trace.
import java.io.StringWriter;
import java.io.PrintWriter;
...
Exception e = new NullPointerException();
StringWriter outError = new StringWriter();
e.printStackTrace(new PrintWriter(outError));
String errorString = outError.toString();
// 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.
|
|
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:
Code section 6.26: Chaining-aware constructor.
try {
lowLevelOp();
} catch (LowLevelException le) {
throw new HighLevelException(le);
}
|
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:
Code section 6.27: Legacy constructor.
try {
lowLevelOp();
} catch (LowLevelException le) {
throw (HighLevelException) new HighLevelException().initCause(le);
}
|
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:
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.
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.
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(...)
.
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:
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.
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.
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 t1
–t2
–t3
, the threads executed in the order of t1
–t3
–t2
. 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.
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();
}
}
}
}
}
|
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?
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. An 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
- ↑ 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.
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.
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.
- By executing a synchronized instance method of that object. See
- 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 thenotify()
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.
methodfinal
void wait()- 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
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.
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.
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:
- The client initiate the connection.
- The server accepts it and sends an acknowledgment notifying that it's ready
- The client sends a request
- The server response based on the request
- ...
- The client sends a
BYE
request - The server acknowledge the
BYE
request and disconnects the socket connection - The client gets the acknowledgment to the
BYE
- The client sends a
- ...
- The client sends a
SHUTDOWN
request - The server acknowledge the
SHUTDOWN
request and disconnects and also stops listening of other clients. - The client gets the acknowledgment to the
SHUTDOWN
- The client sends a
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 communication 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 communication 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.
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:
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:
rmiregistry on Unix
rmiregistry <port> & |
or under Windows:
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:
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:
Code listing 7.10: HelloClient.java
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class HelloClient{
private HelloClient() {}
public static void main(String[] args) {
String host = (args.length < 1) ? null : args[0];
try {
Registry registry = LocateRegistry.getRegistry(host);
Hello stub = (Hello) registry.lookup("Hello");
String response = stub.sayHello();
System.out.println("response: " + response);
} catch (Exception e) {
System.err.println("Client exception: " + e.toString());
e.printStackTrace();
}
}
}
|
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.
Code listing 8.1: Example.java
/**
* A class to give an <b>example</b> of HTML documentation.
*/
public class Example {
/** ...Documentation of a member with the type integer named example... */
public int example;
}
|
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 (@):
Code section 8.1: Documentation comment.
/**
* Get the sum of two integers.
* @param a The first integer number.
* @param b The second integer number.
* @return The value of the sum of the two given integers.
*/
public int sum(int a, int b) {
return a + b;
}
|
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
in the file C:\ProgJava\org\wikibooks\en\Example.java
:
Code listing 8.2: Example.java
package org.wikibooks.en;
/**
* An example class.
*/
public class Example {
/**
Get the sum of two integers.
@param a The first integer number.
@param b The second integer number.
@return The value of the sum of the two given integers.
*/
public int sum(int a, int b) {
return a + b;
}
}
|
The documentation can be generated in a specific folder (C:\ProgDoc for example) with the following command:
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.
Code listing 8.3: C:\ProgJava\org\wikibooks\en\package-info.java
/**
* This fake package is used to illustrate the Java wikibook.
* at <i>en.wikibooks.org</i>.
*/
package org.wikibooks.en;
|
References
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.
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:
Code listing 1.2: Calling of annotation
public class MyMethod
{
@CodeDescription
(
author = "Unknown",
version = "1.0.0.1"
)
public void doSomething()
{
...
}
}
|
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.
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.
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.
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
.
Inherited
Exactly as the name sounds, an @Inherited
annotation type is inherited by subclasses of an annotated type.
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
This section is a stub. You can help Wikibooks by expanding it. |
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:
|
| ||||
|
|
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.
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
|
On the screen
Enter your name: John Doe Welcome, John Doe |
Alternatively, one could write a method to handle keyboard input:
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.
Code listing 9.1: Example of input stream.
import java.io.File;
import java.io.FileInputStream;
public class ConfiguredApplication {
public static void main(String[] args) throws Exception {
// Data reading
File file = new File("source.txt");
FileInputStream stream = new FileInputStream(file);
StringBuffer buffer = new StringBuffer();
int character = 0;
while ((character = stream.read()) != -1) {
buffer.append((char) character);
}
stream.close();
// Data use
Integer readInteger = Integer.parseInt(buffer.toString());
for (int i = 0; i < readInteger ; i++) {
System.out.println("Hello world!");
}
}
}
|
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:
Code listing 9.2: source.txt
4 |
We should obtain this:
Output for ConfiguredApplication
$ java ConfiguredApplication Hello world! Hello world! Hello world! Hello world! |
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.
Code listing 9.2: Example of output stream.
import java.io.File;
import java.io.FileOutputStream;
import java.util.Date;
public class LogTime {
public static void main(String[] args) throws Exception {
// Generate data
String timeInString = new Date().toString();
// Store data
File file = new File("log.txt");
FileOutputStream stream = new FileOutputStream(file);
byte[] timeInBytes = timeInString.getBytes();
stream.write(timeInBytes);
stream.flush();
stream.close();
}
}
|
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.
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:
LogTime execution
$ java LogTime |
We should obtain this content:
Code listing 9.4: log.txt
Thu Dec 19 20:25:13 CEUTC 2024 |
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 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).
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
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:
Code section 1.2: Listener registration
public void add<Event_type>Listener(<Event_type>Listener listener) throws java.util.TooManyListenersException
|
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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: |
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 theFileWriter
. - Implements the
numberStreamTerminated
method by closing theFileWriter
.
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:
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:
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
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.
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.
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.
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?
- Any class that is derived from the
Object
class. - Any class that is derived from the
Component
class. - None of the above.
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?
- The
main(String[])
method. - The
MyCanvas()
method. - The
paint(Graphics)
method. - None of the above.
3
As discussed earlier the paint(Graphics)
method is the correct option. The name says it all.
Graphics
Graphics - Drawing in Java
- Drawing basic shapes
- Drawing complex shapes
- Drawing text
- Understanding gradients
- Anti-aliasing basics
- Interactive drawings
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
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 .
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.
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.
Drawing a simple rectangle
We now proceed on to our second drawing. A simple rectangle would do it justice, see below for code.
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)
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:
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
.redColor
.blueColor
.greenColor
.yellowColor
.pinkColor
.blackColor
.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.
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.
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);
}
...
}
|
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 as you don't have drawCircle(int, int, int)
. Following is the application of Graphics code to draw a circle just to whet your appetite.
drawSquare(int, int, int)
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
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
).
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 theGraphics
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 thesetColor(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?
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);
}
...
- The left and the top outlines disappear.
- The right and the bottom outlines disappear.
- The color for the outline becomes the color for the fill area.
- All the outlines disappear.
All the outlines disappear.
Question 9.4: What would drawLine(10, 100, 100, 100)
give you?
- A horizontal line.
- A vertical line.
- A diagonal line.
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
- Locate the Graphics class in the online Java API documentation
- Locate the Color class in the online Java API documentation
Graphics/Drawing complex shapes
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
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. In 2018, you can use it only from Microsoft Edge's "Compatibility mode" and Firefox Extended Support Release. 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:
Code listing 9.3: HelloWorld.html
<!DOCTYPE html>
<html>
<body>
HTML content before the applet.<applet code="HelloWorld" height="40" width="200"></applet>HTML content after the applet.
</body>
</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
:
Code listing 9.4: HelloWorld.java
import java.applet.Applet;
import java.awt.Graphics;
public class HelloWorld extends Applet {
/**
* Print a message on the screen.
*/
public void paint(Graphics g) {
g.drawString("Hello, world!", 20, 10);
}
}
|
Save this file and compile the class on the same folder. Now let's open the web page on a browser:
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:
Code section 9.10: MyApplet comment
/*
<applet code="MyApplet.class"> </applet>
*/
|
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:
Code section 9.8: A typical init() method
...
public void init() {
setFont(new Font("Times New Roman", Font.PLAIN, 24));
setForeground(Color.white);
setBackground(Color.black);
setLayout(new GridLayout);
...
add(label);
add(button);
}
|
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:
Code section 9.9: Button creation
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.
Code section 9.10: Button display
public void init() {
...
add(submitButton);
}
|
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.
Code section 9.11: Label display
Label nameLabel = new Label("Name: ");
...
public void init() {
add(nameLabel);
}
|
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:
Code section 9.12: Text field creation
TextField t1 = new TextField(); // Blank
TextField t2 = new TextField(5); // Blank in 5 columns
TextField t3 = new TextField("Input here"); // Predefined text
TextField t4 = new TextField("Input here", 5); // Predefined text in 5 columns
...
public void init() {
add(t1);
add(t2);
add(t3);
add(t4);
...
}
|
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:
Code section 9.13: Font setting
Font f = new Font("Times New Roman", Font.PLAIN, 24);
setFont(f);
|
It is not necessary to initialize the font and set the font through two different lines of code.
Code section 9.14: Direct font setting
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:
Code section 9.15: Object font setting
a.setFont(new Font("Times New Roman", Font.PLAIN, 24));
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:
Code section 9.16: Flow Layout
setLayout(new FlowLayout());
|
The added components to the layout that follow will be placed on screen in order of which they are added.
Code section 9.17: Component display
public void init() {
setLayout(new FlowLayout());
add(nameLabel);
add(t1);
add(submitButton);
}
|
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.
Code listing 9.4: GridLayoutApplet.java
import java.applet.Applet;
import java.awt.Button;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.TextField;
public class GridLayoutApplet extends Applet {
Button submitButton = new Button("Submit");
TextField t1 = new TextField(); // Blank
TextField t2 = new TextField(5); // Blank in 5 columns
TextField t3 = new TextField("Input here"); // Predefined text
TextField t4 = new TextField("Input here", 5); // Predefined text in 5 columns
Label nameLabel = new Label("Name: ");
/**
* Init.
*/
public void init() {
// 3 rows, 4 columns, 2 pixel spacing
setLayout(new GridLayout(3, 4, 2, 2));
add(nameLabel);
add(t1);
add(t2);
add(t3);
add(t4);
add(submitButton);
}
}
|
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).
Code section 9.19: Border layout
import java.awt.*;
Container container = getContentPane();
container.setLayout(new BorderLayout());
JButton b2 = new JButton("two");
// Add the button to the right edge.
container.add(b2, BorderLayout.EAST);
...
|
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
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. |
Code listing 9.5: CardLayoutApplet.java
import java.applet.Applet;
import java.awt.CardLayout;
import java.awt.Label;
public class CardLayoutApplet extends Applet {
static final String COMPONENT_POSITION_TOP = "TOP";
static final String COMPONENT_POSITION_MIDDLE = "MIDDLE";
static final String COMPONENT_POSITION_BOTTOM = "BOTTOM";
Label topLabel = new Label("At the top");
Label middleLabel = new Label("In the middle");
Label bottomLabel = new Label("At the bottom");
/**
* Init.
*/
public void init() {
setLayout(new CardLayout());
add(COMPONENT_POSITION_TOP, topLabel);
add(COMPONENT_POSITION_MIDDLE, middleLabel);
add(COMPONENT_POSITION_BOTTOM, bottomLabel);
((CardLayout)getLayout()).show(this, COMPONENT_POSITION_MIDDLE);
}
}
|
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:
Question 9.5: We want to create a basic FTP (File Transfer Protocol) software which looks like this:
Application name | ||||||||||
| ||||||||||
|
| |||||||||
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.
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.
Answer 9.5: Answer5.java
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.Panel;
public class Answer5 extends Applet {
Label applicationNameLabel = new Label("Wikibooks FTP");
Button tool1Button = new Button("Tool");
Button tool2Button = new Button("Tool");
Button tool3Button = new Button("Tool");
Button tool4Button = new Button("Tool");
Button tool5Button = new Button("Tool");
Button tool6Button = new Button("Tool");
Button tool7Button = new Button("Tool");
Button tool8Button = new Button("Tool");
Button tool9Button = new Button("Tool");
Label localFolderLabel = new Label("5 files");
Label remoteFolderLabel = new Label("3 files");
Label statusBarLabel = new Label("Available");
/**
* Init.
*/
public void init() {
setLayout(new BorderLayout());
// The application name
add(applicationNameLabel, BorderLayout.NORTH);
// The center
Panel centerPanel = new Panel();
centerPanel.setLayout(new BorderLayout());
// The buttons
Panel buttonPanel = new Panel();
buttonPanel.setLayout(new FlowLayout(FlowLayout.LEFT));
buttonPanel.add(tool1Button);
buttonPanel.add(tool2Button);
buttonPanel.add(tool3Button);
buttonPanel.add(tool4Button);
buttonPanel.add(tool5Button);
buttonPanel.add(tool6Button);
buttonPanel.add(tool7Button);
buttonPanel.add(tool8Button);
buttonPanel.add(tool9Button);
centerPanel.add(buttonPanel, BorderLayout.CENTER);
// The local and remote folders
Panel folderPanel = new Panel();
folderPanel.setLayout(new GridLayout(0, 2, 2, 2));
folderPanel.add(localFolderLabel);
folderPanel.add(remoteFolderLabel);
centerPanel.add(folderPanel, BorderLayout.SOUTH);
add(centerPanel, BorderLayout.CENTER);
// The status bar
add(statusBarLabel, BorderLayout.SOUTH);
}
}
|
- The totality of the components is put in a border layout so that we have three vertical areas of elements.
- The area in the north is the area of the title.
- The area in the center contains the buttons and the folders and will be split later.
- The area in the south is the area of the status bar.
- 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.
- The button area is then split with a flow layout.
- 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
:
Code listing 9.6: EventApplet.java
import java.applet.Applet;
import java.awt.Button;
import java.awt.Container;
import java.awt.Dialog;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.Label;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class EventApplet extends Applet {
/**
* Init.
*/
public void init() {
Button clickMeButton = new Button("Click me");
final Applet eventApplet = this;
ActionListener specificClassToPerformButtonAction = new ActionListener() {
public void actionPerformed(ActionEvent event) {
Dialog dialog = new Dialog(getParentFrame(eventApplet), false);
dialog.setLayout(new FlowLayout());
dialog.add(new Label("Hi!!!"));
dialog.pack();
dialog.setLocation(100, 100);
dialog.setVisible(true);
}
private Frame getParentFrame(Container container) {
if (container == null) {
return null;
} else if (container instanceof Frame) {
return (Frame) container;
} else {
return getParentFrame(container.getParent());
}
}
};
clickMeButton.addActionListener(specificClassToPerformButtonAction);
add(clickMeButton);
}
}
|
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 its subcomponents), 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
Console
java fully-qualified-class-name arg0 ... argn |
and pass it command line arguments, the JRE must
- put the command line arguments arg0 ... argn into a
String
[] array - dynamically load the target class named by fully-qualified-class-name
- access the
public
static
void
main(String[])
method - invoke the
main
method, passing the string array mainString[]
.
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.
Code section 10.1: main() method invocation.
public static void invokeMain()
throws ClassNotFoundException,
ExceptionInInitializerError,
IllegalAccessException,
IllegalArgumentException,
InvocationTargetException,
NoSuchMethodException,
SecurityException {
Class<?> distanceClass = Class.forName("Distance");
String[] points = {"0", "0", "3", "4"};
Method mainMethod = distanceClass.getMethod("main", String[].class);
Object result = mainMethod.invoke(null, (Object) points);
}
|
This code is obviously more complicated than simply calling
Code section 10.2: main() method calling.
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.
Code section 10.3: invoke() call.
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 throwClassNotFoundException
, if the named class cannot be located.Class.forName(String)
will throwExceptionInInitializerError
, if the class could not be loaded due to the static initializer throwing an exception or a static field's initialization throwing an exception.Class.getMethod(String name, Class parameterTypes[])
will throwNoSuchMethodException
, if a matching method is not found, or is not public (usegetDeclaredMethod
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 thesun.*
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):
Code section 10.4: Class loader.
URLClassLoader classLoader = URLClassLoader.newInstance(
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:
Code section 10.5: Class loading.
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:
Code listing 10.1: DummyTo.java
package com.test;
public class DummyTo {
private String name;
private String address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public DummyTo(String name, String address) {
this.name = name;
this.address = address;
}
public DummyTo() {
this.name = new String();
this.address = new String();
}
public String toString(String appendBefore) {
return appendBefore + " " + name + ", " + address;
}
}
|
Following is the example for invoking method from the above mentioned to dynamically. Code is self explanatory.
|
|
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:
Code listing 10.3: Secret.java
public class Secret {
private String secretCode = "It's a secret";
private String getSecretCode() {
return secretCode;
}
}
|
Although the field and method are marked private
, the following class shows that it is possible to access the private
features of a class:
|
|
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 [dead link] 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].
- ↑ What's the best way of unit testing private methods?, March 7, 2011
- ↑ Reflection API injected at compile-time [dead link]
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 |
Remote Method Invocation (RMI) |
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:
- find(): find the next result.
- 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
This section is a stub. You can help Wikibooks by expanding it. |
Libraries
Libraries, Extensions, and Frameworks
- Math and Geometry
- Regular Expressions
- Security
- Input and Output
- XML
- Graphical User Interfaces
- Open Source
3D Programming
This page or section is an undeveloped draft or outline. You can help to develop the work, or you can ask for assistance in the project room. |
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 3D
- JOGL
- JPCT
- Light Weight Java Game Library
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 |
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
Code listing 10.1: HelloWorld.java
public class HelloWorld {
private native void print();
public static void main(String[] args) {
new HelloWorld().print();
}
static {
System.loadLibrary("HelloWorld");
}
}
|
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
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 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:
Compilation
$ cc test.c -o test |
Then invoke the C program using this Java code:
Code listing 10.2: Invoking C programs.
import java.io.InputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.InterruptedException;
import java.io.Process;
import java.io.Runtime;
import java.util.ArrayList;
public class ExecDemo {
public static String[] runCommand(String cmd) throws IOException {
// --- set up list to capture command output lines ---
ArrayList list = new ArrayList();
// --- start command running
Process proc = Runtime.getRuntime().exec(cmd);
// --- get command's output stream and
// put a buffered reader input stream on it ---
InputStream istr = proc.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(istr));
// --- read output lines from command
String str;
while ((str = br.readLine()) != null) {
list.add(str);
}
// wait for command to terminate
try {
proc.waitFor();
}
catch (InterruptedException e) {
System.err.println("process was interrupted");
}
// check its exit value
if (proc.exitValue() != 0) {
System.err.println("exit value was non-zero");
}
// close stream
br.close();
// return list of strings to caller
return (String[])list.toArray(new String[0]);
}
public static void main(String args[]) throws IOException {
try {
// run a command
String outlist[] = runCommand("test");
// display its output
for (int i = 0; i < outlist.length; i++)
System.out.println(outlist[i]);
}
catch (IOException e) {
System.err.println(e);
}
}
}
|
The demo calls a method runCommand
to actually run the program.
Code section 10.1: Running a command.
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.
Code section 10.2: Reading the program's output.
InputStream istr = proc.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(istr));
String str;
while ((str = br.readLine()) != null) {
list.add(str);
}
|
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) |
invokedynamic | ba | indexbyte1, indexbyte2 | [arg1, arg2, ...] → result | invokes a dynamic method and puts the result on the stack (might be void); the method is identified by method 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 | ||||
W | ||||
Unused | ||||
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
External Links
- Bytecode Visualizer - free Eclipse plugin for visualizing and debugging Java bytecode
- Bytecode Outline plugin for Eclipse by ObjectWeb
- Easy illustration to fill the gap between JVM, its purpose and advantages vs JIT Compiling
Appendices
Links
External References
- Java Certification Preparation Guides
- Java Certification Mock Exams 500+ questions with exam simulator (this is the older 1.4 version of the exam)
- Java Language Specification.
- Thinking in Java
- Java 8 SDK Documentation
- Java 5 SDK Documentation in CHM Format
- Java 8 API Documentation
- The Java Tutorial
- Sun Developer Network New to Java Center
- A simple Java Tutorial
- Two Semesters of College-Level Java Lectures--Free
- Java Lessons - Interactive Java programming tutorials based on examples
- Java Tutorials for Kids and Adults
External links
- Introduction to Programming Using Java by David J. Eck
- Think Java by Allen Downey and Chris Mayfield
- Introduction to Computer Science using Java by Bradley Kjell
- Learn Java - ad-supported site with tutorials for many languages
- Java Certification Mock Exams 500+ questions with exam simulator
- SwingWiki - Open documentation project containing tips, tricks and best practices for Java Swing development
- JavaTips - Blog project containing best JAVA tips and tricks
- Free Java/ Advanced Java Books
- Free Java and J2EE eBooks
- Java books available for free downloads
- Roedy Green's Java & Internet Glossary A comprehensive reference that's also an excellent starting point for beginners
- C2: Java Language
- NetBeans IDE
- Eclipse IDE
- Zeus for Windows IDE
- Official Java Home Site
- Original Java Whitepaper
- Complete Java Programming Tutorials
- Javapassion, Java course - The Javapassion Site, Java Course, driven by Sang Shin from Sun
- beanshell Interpreted version
- The Java Language Specification, Third Edition "This book attempts a complete specification of the syntax and semantics of the language."
- The Java Virtual Machine Specification, Second Edition and amendments
- A pure java desktop
- Javapedia project
- Bruce Eckel Thinking in Java Third edition -- [7] (Bruce has a C/C++ free book available on-line too)
- JavaGameDevelopment Daily news and articles on Java Game Development
- Java Certifications Site(SCJP,SCWCD,SCBCD,Java 5.0,SCEA
- Java Programming FAQs and Tutorials
- More resources
- Java lessons
- Online Java Tutorial
- Full Java Tutorial - A collection of free premium programming tutorials
- Java Certification Practice Tests and Articles
- Kode Java - Learn Java Programming by Examples
- Games Programming Wiki - Java tutorials and lessons based on game programming
- WikiJava - Examples and tutorials in Java
- Download Free java ebooks from 83 ebooks collection - Free Java Ebooks to download from ebookslab.info
- Download Free Sun Certified Developer for Java Web Services - Free Java Ebooks to download from ebooks.mzwriter.net
- Code Conventions for the Java Programming Language - At SUN
- Java Lessons at LeoLoL - A collection of introductory lessons to Java
- Java Exercises at LeoLoL - A collection of Java exercises with sample solutions
- Java Best Practices - A collection of Java tutorials, best practices and programming tips
Newsgroups:
Glossary
This is a glossary of the book.
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[check spelling] a particular class about its methods and their parameters.
Index
This is an alphabetical index to the book about basic java.
ABCDE
FGI |
KLMNOPQRSTV |
GNU Free Documentation License
As of July 15, 2009 Wikibooks has moved to a dual-licensing system that supersedes the previous GFDL only licensing. In short, this means that text licensed under the GFDL only can no longer be imported to Wikibooks, retroactive to 1 November 2008. Additionally, Wikibooks text might or might not now be exportable under the GFDL depending on whether or not any content was added and not removed since July 15. |
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:
- 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.
- 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.
- State on the Title page the name of the publisher of the Modified Version, as the publisher.
- Preserve all the copyright notices of the Document.
- Add an appropriate copyright notice for your modifications adjacent to the other copyright notices.
- 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.
- Preserve in that license notice the full lists of Invariant Sections and required Cover Texts given in the Document's license notice.
- Include an unaltered copy of this License.
- 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.
- 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.
- 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.
- 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.
- Delete any section Entitled "Endorsements". Such a section may not be included in the Modified version.
- Do not retitle any existing section to be Entitled "Endorsements" or to conflict in title with any Invariant Section.
- 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.