Enter your email address:

Delivered by FeedBurner


Thursday, March 29, 2012

Java Date and Time Tutorial

The Java date and time API's can be rather confusing when you first try to figure out how to use it. Therefore I have put together this little trail on Java's date and time classes. Hopefully that will help you get an overview of Java's date and time classes. I also hope it may clear up some of the confusion Sun has created with Java's many date and time classes.
Java has the following date and time classes and methods. Each of these classes are also explained in their own pages, later. See the links at the bottom of this page, or at the top right of every page.

System.currentTimeMillis() A static method that returns the current date and time as milliseconds since January 1st 1970
java.util.Date A class that represents a date and time. Most methods in this class is deprecated.
java.sql.Date A class that represents a date. All time information cut off. This date class is used with JDBC.
java.sql.Timestamp A class that represents a date and time. This date and time class is used with JDBC.
java.util.Calendar A base class for calendar classes. Has methods to do date and time arithmethics like adding a day or month to another date.
java.util.GregorianCalendar A concrete class subclassing java.util.Calendar, representing the Gregorian calendar which is used in most of the western world today. Has all the methods from java.util.Calendar to do date and time arithmethics.
java.util.TimeZone The Java TimeZone class is a class that represents time zones, and is helpful when doing calendar arithmetics across time zones.
java.text.SimpleDateFormat A class that can help you parse String's into Date's, and format Date's as String's.

So, which of all these classes should you use? Well, that depends on what you are trying to do.
If you need to do simple timing the System.currentTimeMillis() method will do just fine.
If you just need an object to hold a date, for instance as a property in a simple domain model object, you can use the java.util.Date class.
If you need to read and write the date and time to a database, use the java.sql.Date and java.sql.Timestamp classes.
If you need to do date calculations like adding days or months to another date, or check what weekday (monday, tuesday etc.) a given date is, or convert dates and times between time zones, use the java.util.Calendar and java.util.GregorianCalendar classes.
Here is a list of the texts in this Java date and time tutorial. This list also available in the upper right side of all pages, so you can easily navigate between them.
  Java Date and Time


Java Date and Time Introduction

System.currentTimeMillis()

Time Measurement

java.util.Date

java.sql.Date

java.sql.Timestamp

java.util.Calendar

java.util.TimeZone

Parsing and Formatting Dates

Implementing hashCode() and equals()

The methods hashCode() and equals() play a distinct role in the objects you insert into Java collections. The specific contract rules of these two methods are best described in the JavaDoc. Here I will just tell you what role they play. What they are used for, so you know why their implementations are important.

equals()

equals() is used in most collections to determine if a collection contains a given element. For instance:
List list = new ArrayList();
list.add("123");

boolean contains123 = list.contains("123");
The ArrayList iterates all its elements and execute "123".equals(element) to determine if the element is equal to the parameter object "123". It is the String.equals() implementation that determines if two strings are equal.
The equals() method is also used when removing elements. For instance:
List list = new ArrayList();
list.add("123");

boolean removed = list.remove("123");
The ArrayList again iterates all its elements and execute "123".equals(element) to determine if the element is equal to the parameter object "123". The first element it finds that is equal to the given parameter "123" is removed.
As you can see, a proper implementation of .equals() is essential for your own classes to work well with the Java Collection classes. So how do you implement equals() "properly"?
So, when are two objects equal? That depends on your application, the classes, and what you are trying to do. For instance, let's say you are loading and processing Employee objects stored in a database. Here is a simple example of such an Employee class:
public class Employee {
    protected long   employeeId;
    protected String firstName;
    protected String lastName;
}
You could decide that two Employee objects are equal to each other if just their employeeId's are equal. Or, you could decide that all fields must be equal - both employeeId, firstName and lastName. Here are two example implementation of equals() matching these criterias:
public class Employee {
  ...
  public boolean equals(Object o){
    if(o == null)                return false;
    if(!(o instanceof) Employee) return false;

    Employee other = (Employee) o;
    return this.employeeId == other.employeeId;
  }
}
public class Employee {
  ...
  public boolean equals(Object o){
    if(o == null)                return false;
    if(!(o instanceof) Employee) return false;

    Employee other = (Employee) o;
    if(this.employeeId != other.employeeId)      return false;
    if(! this.firstName.equals(other.firstName)) return false;
    if(! this.lastName.equals(other.lastName))   return false;

    return true;
  }
}
Which of these two implementations is "proper" depends on what you need to do. Sometimes you need to lookup an Employee object from a cache. In that case perhaps all you need is for the employeeId to be equal. In other cases you may need more than that - for instance to determine if a copy of an Employee object has changed from the original.

hashCode()

The hashCode() method of objects is used when you insert them into a HashTable, HashMap or HashSet. If you do not know the theory of how a hashtable works internally, you can read about hastables on Wikipedia.org.
When inserting an object into a hastable you use a key. The hash code of this key is calculated, and used to determine where to store the object internally. When you need to lookup an object in a hashtable you also use a key. The hash code of this key is calculated and used to determine where to search for the object.
The hash code only points to a certain "area" (or list, bucket etc) internally. Since different key objects could potentially have the same hash code, the hash code itself is no guarantee that the right key is found. The hashtable then iterates this area (all keys with the same hash code) and uses the key's equals() method to find the right key. Once the right key is found, the object stored for that key is returned.
So, as you can see, a combination of the hashCode() and equals() methods are used when storing and when looking up objects in a hashtable.
Here are two rules that are good to know about implementing the hashCode() method in your own classes, if the hashtables in the Java Collections API are to work correctly:
  1. If object1 and object2 are equal according to their equals() method, they must also have the same hash code.
  2. If object1 and object2 have the same hash code, they do NOT have to be equal too.
In shorter words:
  1. If equal, then same hash codes too.
  2. Same hash codes no guarantee of being equal.
Here are two example implementation of the hashCode() method matching the equals() methods shown earlier:
public class Employee {
  protected long   employeeId;
  protected String firstName;
  protected String lastName;

  public int hashCode(){
    return (int) this.employeeId;
  }
}
public class Employee {
    protected long   employeeId;
    protected String firstName;
    protected String lastName;

  public int hashCode(Object o){
    return (int)this.employeeId *
                firstName.hashCode() *
                lastName.hashCode();
  }
}
Notice, that if two Employee objects are equal, they will also have the same hash code. But, as is especially easy to see in the first example, two Employee objects can be not equal, and still have the same hash code.
In both examples the hash code is the employeeId is rounded down to an int. That means that many employee id's could result in the same hash code, but these Employee objects would still not be equal, since they don't have the same employee id.

More Detail in the JavaDoc

For a 100% precise description of how to implement equals() and hashCode() you should check out the official JavaDoc's. The purpose of this text was mostly to explain how they are used by the Java Collection classes. Understanding this makes it easier to implement them to suit your purposes.

Java's Stack Class



The java.util.Stack class deserves a little explanation on its own. In the text on the List interface the Stack class is listed as an implementation. The typical use of a Stack is not as a List though.
A Stack is a data structure where you add elements to the "top" of the stack, and also remove elements from the top again. This is also referred to as the "Last In First Out (LIFO)" principle. In contrast, a Queue uses a "First In First Out (FIFO)" principle.
Stack's are really handy for some types of data processing, for instance if you are parsing an XML file using either SAX or StAX. For an example, see my Java SAX Example in my Java XML tutorial.
Here is a Stack usage example:
Stack stack = new Stack();

stack.push("1");
stack.push("2");
stack.push("3");

//look at top object ("3"), without taking it off the stack.    
Object objTop = stack.peek();

Object obj3 = stack.pop(); //the string "3" is at the top of the stack.
Object obj2 = stack.pop(); //the string "2" is at the top of the stack.
Object obj1 = stack.pop(); //the string "1" is at the top of the stack.   
The push() method pushes an object onto the top of the Stack.
The peek() method returns the object at the top of the Stack, but leaves the object on of the Stack.
The pop() method returns the object at the top of the stack, and removes the object from the Stack.

Searching the Stack

You can search for an object on the stack to get it's index, using the search() method. The object's equals() method is called on every object on the Stack to determine if the searched-for object is present on the Stack. The index you get is the index from the top of the Stack, meaning the top element on the Stack has index 1.
Here is how you search a Stack for an object:
Stack stack = new Stack();

stack.push("1");
stack.push("2");
stack.push("3");

int index = stack.search("3");     //index = 3

Java's Deque Interface

The java.util.Deque interface is a subtype of the java.util.Queue interface. It represents a queue where you can insert and remove elements from both ends of the queue. Thus, "Deque" is short for "Double Ended Queue" and is pronounced "deck", like a deck of cards.
Here is a list of the topics covered in this text:
  1. Deque Implementations
  2. Adding and Accessing Elements
  3. Removing Elements
  4. Generic Deques
  5. More Details in the JavaDoc

Deque Implementations

Being a Queue subtype all methods in the Queue and Collection interfaces are also available in the Deque interface.
Since Deque is an interface you need to instantiate a concrete implementation of the interface in order to use it. You can choose between the following Deque implementations in the Java Collections API:
  • java.util.ArrayDeque
  • java.util.LinkedList
LinkedList is a pretty standard deque / queue implementation.
ArrayDeque stores its elements internally in an array. If the number of elements exceeds the space in the array, a new array is allocated, and all elements moved over. In other words, the ArrayDeque grows as needed, even if it stores its elements in an array.
There are also Queue implementations in the java.util.concurrent package, but I will leave the concurrency utilities out of this tutorial.
Here are a few examples of how to create a Deque instance:
Deque dequeA = new LinkedList();
Deque dequeB = new ArrayDeque();

Adding and Accessing Elements

To add elements to the tail of a Deque you call its add() method. You can also use the addFirst() and addLast() methods, which add elements to the head and tail of the deque.
Deque dequeA = new LinkedList();

dequeA.add     ("element 1"); //add element at tail
dequeA.addFirst("element 2"); //add element at head
dequeA.addLast ("element 3"); //add element at tail
The order in which the elements added to the Deque are stored internally, depends on the implementation. The two implementations mentioned earlier both store the elements in the order (first or last) in which they are inserted.
You can peek at the element at the head of the queue without taking the element out of the queue. This is done via the element() method. You can also use the getFirst and getLast() methods, which return the first and last element in the Deque. Here is how that looks:
Object firstElement = dequeA.element();
Object firstElement = dequeA.getFirst();
Object lastElement  = dequeA.getLast();
Taking elements from the deque is covered later.
You can also iterate all elements of a deque, instead of just processing one at a time. Here is how that looks:
Deque dequeA = new LinkedList();

dequeA.add("element 0");
dequeA.add("element 1");
dequeA.add("element 2");

//access via Iterator
Iterator iterator = dequeA.iterator();
while(iterator.hasNext(){
  String element = (String) iterator.next();
}

//access via new for-loop
for(Object object : dequeA) {
    String element = (String) object;
}
When iterating the deque via its Iterator or via the for-loop (which also uses the Iterator behind the scene, the sequence in which the elements are iterated depends on the deque implementation.

Removing Elements

To remove elements from a deque, you call the remove(), removeFirst() and removeLast methods. Here are a few examples:
Object firstElement = dequeA.remove();
Object firstElement = dequeA.removeFirst();
Object lastElement  = dequeA.removeLast();

Generic Deque

By default you can put any Object into a Deque, but from Java 5, Java Generics makes it possible to limit the types of object you can insert into a Deque. Here is an example:
Deque<MyObject> deque = new LinkedList<MyObject>();
This Deque can now only have MyObject instances inserted into it. You can then access and iterate its elements without casting them. Here is how it looks:
MyObject myObject = deque.remove();

for(MyObject anObject : deque){
   //do someting to anObject...   
}
For more information about Java Generics, see the Java Generics Tutorial.

More Details in the JavaDoc

There is a lot more you can do with a Deque, but you will have to check out the JavaDoc for more details. This text focused on the two most common operations: Adding / removing elements, and iterating the elements.

Java's Queue Interface

The java.util.Queue interface is a subtype of the java.util.Collection interface. It represents an ordered list of objects just like a List, but its intended use is slightly different. A queue is designed to have elements inserted at the end of the queue, and elements removed from the beginning of the queue. Just like a queue in a supermarket.
Here is a list of the topics covered in this text:
  1. Queue Implementations
  2. Adding and Accessing Elements
  3. Removing Elements
  4. Generic Queues
  5. More Details in the JavaDoc

Queue Implementations

Being a Collection subtype all methods in the Collection interface are also available in the Queue interface.
Since Queue is an interface you need to instantiate a concrete implementation of the interface in order to use it. You can choose between the following Queue implementations in the Java Collections API:
  • java.util.LinkedList
  • java.util.PriorityQueue
LinkedList is a pretty standard queue implementation.
PriorityQueue stores its elements internally according to their natural order (if they implement Comparable), or according to a Comparator passed to the PriorityQueue.
There are also Queue implementations in the java.util.concurrent package, but I will leave the concurrency utilities out of this tutorial.
Here are a few examples of how to create a Queue instance:
Queue queueA = new LinkedList();
Queue queueB = new PriorityQueue();

Adding and Accessing Elements

To add elements to a Queue you call its add() method. This method is inherited from the Collection interface. Here are a few examples:
Queue queueA = new LinkedList();

queueA.add("element 1");
queueA.add("element 2");
queueA.add("element 3");
The order in which the elements added to the Queue are stored internally, depends on the implementation. The same is true for the order in which elements are retrieved from the queue. You should consult the JavaDoc's for more information about the specific Queue implementations.
You can peek at the element at the head of the queue without taking the element out of the queue. This is done via the element() method. Here is how that looks:
Object firstElement = queueA.element();
To take the first element out of the queue, you use the remove() method which is described later.
You can also iterate all elements of a queue, instead of just processing one at a time. Here is how that looks:
Queue queueA = new LinkedList();

queueA.add("element 0");
queueA.add("element 1");
queueA.add("element 2");

//access via Iterator
Iterator iterator = queueA.iterator();
while(iterator.hasNext(){
  String element = (String) iterator.next();
}

//access via new for-loop
for(Object object : queueA) {
    String element = (String) object;
}
When iterating the queue via its Iterator or via the for-loop (which also uses the Iterator behind the scene, the sequence in which the elements are iterated depends on the queue implementation.

Removing Elements

To remove elements from a queue, you call the remove() method. This method removes the element at the head of the queue. In most Queue implementations the head and tail of the queue are at opposite ends. It is possible, however, to implement the Queue interface so that the head and tail of the queue is in the same end. In that case you would have a stack.
Here is a remove example();
Object firstElement = queueA.remove();

Generic Queue

By default you can put any Object into a Queue, but from Java 5, Java Generics makes it possible to limit the types of object you can insert into a Queue. Here is an example:
Queue<MyObject> queue = new LinkedList<MyObject>();
This Queue can now only have MyObject instances inserted into it. You can then access and iterate its elements without casting them. Here is how it looks:
MyObject myObject = queue.remove();

for(MyObject anObject : queue){
   //do someting to anObject...   
}
For more information about Java Generics, see the Java Generics Tutorial.

More Details in the JavaDoc

There is a lot more you can do with a Queue, but you will have to check out the JavaDoc for more details. This text focused on the two most common operations: Adding / removing elements, and iterating the elements.

Java's NavigableMap Interface

The java.util.NavigableMap interface is a subtype of the java.util.SortedMap interface. It has a few extensions to the SortedSet which makes it possible to navigate the map. I will take a closer look at these navigation methods in this text.
The java.util package only has one implementation of the NavigableMap interface: java.util.TreeMap. There is an implementation in the java.util.concurrent package but that is outside the scope of this trail.
Here is a list of the topics covered in this text:
  1. descendingKeySet() and descendingMap()
  2. headMap(), tailMap() and subMap()
  3. ceilingKey(), floorKey(), higherKey() and lowerKey()
  4. ceilingEntry(), floorEntry(), higherEntry() and lowerEntry()
  5. pollFirstEntry() and pollLastEntry()
  6. More detail in the JavaDoc

descendingKeySet() and descendingMap()

The first interesting navigation methods are the descendingKeySet() and descendingMap() methods.
The descendingKeySet() method returns a NavigableSet in which the order of the elements is reversed compared to the original key set. The returned "view" is backed by the original NavigableSet ket set, so changes to the descending set are also reflected in the original set. However, you should not remove elements directly from the key set. Use the Map.remove() method instead.
Here is a simple example:
NavigableSet reverse = map.descendingKeySet();
The descendingMap() method returns a NavigableMap which is a view of the original Map. The order of the elements in this view map is reverse of the order of the original map. Being a view of the original map, any changes to this view is also reflected in the original map.
Here is a simple example:
NavigableMap descending = map.descendingMap();

headMap(), tailMap() and subMap()

The headMap() method returns a view of the original NavigableMap which only contains elements that are "less than" the given element. Here is an example:
NavigableMap original = new TreeMap();
original.put("1", "1");
original.put("2", "2");
original.put("3", "3");

//this headmap1 will contain "1" and "2"
SortedMap headmap1 = original.headMap("3");

//this headmap2 will contain "1", "2", and "3" because "inclusive"=true
NavigableMap headmap2 = original.headMap("3", true);
The tailMap() method works the same way, except it returns all elements that are higher than the given parameter element.
The subMap() allows you to pass two parameters demarcating the boundaries of the view map to return. Here is an example:
NavigableMap original = new TreeMap();
original.put("1", "1");
original.add("2", "2");
original.add("3", "3");
original.add("4", "4");
original.add("5", "5");

//this submap1 will contain "3", "3"
SortedMap    submap1  = original.subMap("2", "4");

//this submap2 will contain ("2", "2") ("3", "3") and ("4", "4") because
//    fromInclusive=true, and toInclusive=true
NavigableMap submap2 = original.subMap("2", true, "4", true);

ceilingKey(), floorKey(), higherKey() and lowerKey()

The ceilingKey() method returns the least (smallest) key in this map that is greater than or equal to the element passed as parameter to the ceilingKey() method. Here is an example:
NavigableMap original = new TreeMap();
original.put("1", "1");
original.put("2", "2");
original.put("3", "3");


//ceilingKey will be "2".
Object ceilingKey = original.ceilingKey("2");

//floorKey will be "2".
Object floorKey = original.floorKey("2");
The floorKey() method does the opposite of ceilingKey()
The higherKey() method returns the least (smallest) element in this map that is greater than (not equal too) the element passed as parameter to the higherKey() method. Here is an example:
NavigableMap original = new TreeMap();
original.put("1", "1");
original.put("2", "2");
original.put("3", "3");


//higherKey will be "3".
Object higherKey = original.higherKey("2");

//lowerKey will be "1"
Object lowerKey = original.lowerKey("2");
The lowerKey() method does the opposite of the higherKey() method.

celingEntry(), floorEntry(), higherEntry(), lowerEntry()

The NavigableMap also has methods to get the entry for a given key, rather than the key itself. These methods behave like the ceilingKey() etc. methods, except they return an Map.Entry instead of the key object itself.
A Map.Entry maps a single key to a single value.
Here is a simple example. For more details, check out the JavaDoc.
NavigableMap original = new TreeMap();
original.put("1", "1");
original.put("2", "2");
original.put("3", "3");


//higherEntry will be ("3", "3").
Map.Entry higherEntry = original.higherEntry("2");

//lowerEntry will be ("1", "1")
Map.Entry lowerEntry = original.lowerEntry("2");

pollFirstEntry() and pollLastEntry()

The pollFirstEntry() method returns and removes the "first" entry (key + value) in the NavigableMap or null if the map is empty. The pollLastEntry() returns and removes the "last" element in the map or null if the map is empty. "First" means smallest element according to the sort order of the keys. "Last" means largest key according to the element sorting order of the map.
Here are two examples:
NavigableMap original = new TreeMap();
original.put("1", "1");
original.put("2", "2");
original.put("3", "3");


//first is ("1", "1")
Map.Entry first = original.pollFirstEntry();

//last is ("3", "3")
Map.Entry last = original.pollLastEntry();

More Detail in the JavaDoc

There are still a few interesting methods left in the NavigableMap interface that I have not covered here. For instance, the firstEntry() and lastEntry() methods. You can check out these last methods in the official JavaDoc.


Java's SortedMap Interface

The java.util.SortedMap interface is a subtype of the java.util.Map interface, with the addition that the elements stored in the map are sorted internally.
The order of the sorting is either the natural sorting order of the elements (if they implement java.lang.Comparable), or the order determined by a Comparator that you can give to the SortedSet.
By default the elements are iterated in ascending order, starting with the "smallest" and moving towards the "largest". But it is also possible to iterate the elements in descending order using the method TreeMap.descendingKeySet().
The Java Collections API only has one implementation of the SortedMap interface - the java.util.TreeMap class. The java.util.concurrent package also has an implementation of this interface, but I will leave the concurrency utilities out of this trail.
Here are two examples of how to create a SortedMap:
SortedMap mapA = new TreeMap();

Comparator comparator = new MyComparator();
SortedMap mapB = new TreeMap(comparator);

More Details in the JavaDoc

There is actually a lot more you can do with a TreeMap that is not part of the SortedMap interface, like getting a descending key set etc. Check out the JavaDoc's for more detail about these features.

Java's Map Interface

The java.util.Map interface represents a mapping between a key and a value. The Map interface is not a subtype of the Collection interface. Therefore it behaves a bit different from the rest of the collection types.
Here is a list of the topics covered in this text:
  1. Map Implementations
  2. Adding and Accessing Elements
  3. Removing Elements
  4. Generic Maps
  5. More Details in the JavaDoc

Map Implementations

Since Map is an interface you need to instantiate a concrete implementation of the interface in order to use it. You can choose between the following Map implementations in the Java Collections API:
  • java.util.HashMap
  • java.util.Hashtable
  • java.util.EnumMap
  • java.util.IdentityHashMap
  • java.util.LinkedHashMap
  • java.util.Properties
  • java.util.TreeMap
  • java.util.WeakHashMap
In my experience, the most commonly used Map implementations are HashMap and TreeMap.
Each of these Set implementations behaves a little differently with respect to the order of the elements when iterating the Set, and the time (big O notation) it takes to insert and access elements in the sets.
HashMap maps a key and a value. It does not guarantee any order of the elements stored internally in the map.
TreeMap also maps a key and a value. Furthermore it guarantees the order in which keys or values are iterated - which is the sort order of the keys or values. Check out the JavaDoc for more details.
Here are a few examples of how to create a Map instance:
Map mapA = new HashMap();
Map mapB = new TreeMap();

Adding and Accessing Elements

To add elements to a Map you call its put() method. Here are a few examples:
Map mapA = new HashMap();

mapA.put("key1", "element 1");
mapA.put("key2", "element 2");
mapA.put("key3", "element 3");
The three put() calls maps a string value to a string key. You can then obtain the value using the key. To do that you use the get() method like this:
String element1 = (String) mapA.get("key1");
You can iterate either the keys or the values of a Map. Here is how you do that:
// key iterator
Iterator iterator = mapA.keySet().iterator();

// value iterator
Iterator iterator = mapA.values();
Most often you iterate the keys of the Map and then get the corresponding values during the iteration. Here is how it looks:
Iterator iterator = mapA.keySet().iterator();
while(iterator.hasNext(){
  Object key   = iterator.next();
  Object value = mapA.get(key);
}

//access via new for-loop
for(Object key : mapA.keySet()) {
    Object value = mapA.get(key);
}

Removing Elements

You remove elements by calling the remove(Object key) method. You thus remove the (key, value) pair matching the key.

Generic Maps

By default you can put any Object into a Map, but from Java 5, Java Generics makes it possible to limit the types of object you can use for both keys and values in a Map. Here is an example:
Map<String, MyObject> map = new HashSet<String, MyObject>();
This Map can now only accept String objects for keys, and MyObject instances for values. You can then access and iterate keys and values without casting them. Here is how it looks:
for(MyObject anObject : map.values()){
   //do someting to anObject...
}

for(String key : map.keySet()){
   MyObject value = map.get(key);
   //do something to value
}
For more information about Java Generics, see the Java Generics Tutorial.

More Details in the JavaDoc

There is more you can do with a Map, but you will have to check out the JavaDoc for more details. This text focused on the two most common operations: Adding / removing elements, and iterating the keys and values.

Java's NavigableSet Interface

The java.util.NavigableSet interface is a subtype of the java.util.SortedSet interface. It behaves like a SortedSet with the exception you have navigation methods available in addition to the sorting mechanisms of the SortedSet. In this text I will look closer at some of these navigation methods.
In Java 6 there is only one implementation of the NavigableSet interface in the java.util package: java.util.TreeSet There is an implementation in the java.util.concurrent package but that is outside the scope of this trail.
Here is a list of the topics covered in this text:
  1. descendingIterator() and descendingSet()
  2. headSet(), tailSet() and subSet()
  3. ceiling(), floor(), higher() and lower()
  4. pollFirst() and pollLast()

descendingIterator() and descendingSet()

The first interesting navigation methods are the descendingIterator() and descendingSet() methods.
The descendingSet() method returns a NavigableSet in which the order of the elements is reversed compared to this one. The returned "view" is backed by the original NavigableSet, so changes to the descending set are also reflected in the original set.
Here is a simple example:
NavigableSet reverse = original.descendingSet();
The descendingIterator() method allows you to iterate the elements of the NavigableSet (which is also a SortedSet) in reverse order, without changing the order of the elements internally.
Iterator reverse = original.descendingIterator();    

headSet(), tailSet() and subSet()

The headSet() method returns a view of the original NavigableSet which only contains elements that are "less than" the given element. Here is an example:
NavigableSet original = new TreeSet();
original.add("1");
original.add("2");
original.add("3");

//this headset will contain "1" and "2"
SortedSet headset = original.headSet("3");

//this headset will contain "1", "2", and "3" because "inclusive"=true
NavigableSet headset = original.headSet("3", true);
The tailSet() method works the same way, except it returns all elements that are higher than the given parameter element.
The subSet() allows you to pass two parameters demarcating the boundaries of the view set to return. The elements matching the first boundary is included, where as elements matching the last boundary are not. Here is an example:
NavigableSet original = new TreeSet();
original.add("1");
original.add("2");
original.add("3");
original.add("4");
original.add("5");

//this subset will contain "2" and "3"
SortedSet    subset  = original.subSet("2", "4");

//this subset will contain "2", "3" and "4" because
//    fromInclusive=true, and toInclusive=true 
NavigableSet subset = original.subSet("2", true, "4", true);

ceiling(), floor(), higher(), and lower()

The ceiling() method returns the least (smallest) element in this set that is greater than or equal to the element passed as parameter to the ceiling() method. Here is an example:
NavigableSet original = new TreeSet();
original.add("1");
original.add("2");
original.add("3");


//ceiling will be "2".
Object ceiling = original.ceiling("2");

//floor will be "2".
Object floor = original.floor("2");
The floor() method does the opposite of ceiling()
The higher() method returns the least (smallest) element in this set that is greater than (not equal too) the element passed as parameter to the higher() method. Here is an example:
NavigableSet original = new TreeSet();
original.add("1");
original.add("2");
original.add("3");


//higher will be "3".
Object higher = original.higher("2");

//lower will be "1"
Object lower = original.lower("2");
The lower() method does the opposite of the higher() method.

pollFirst() and pollLast()

The pollFirst() method returns and removes the "first" element in the NavigableSet or null if the set is empty. The pollLast() returns and removes the "last" element in the set or null if the set is empty. "First" means smallest element according to the sort order of the set. "Last" means largest according to teh element sorting order of the set.
Here are two examples:
NavigableSet original = new TreeSet();
original.add("1");
original.add("2");
original.add("3");


//first is "1"
Object first = original.pollFirst();

//last is "3"
Object last = original.pollLast();

Java's SortedSet Interface

The java.util.SortedSet interface is a subtype of the java.util.Set interface. It behaves like a normal set with the exception that the elements are sorted internally. This means that when you iterate the elements of a SortedSet the elements are returned in the sorted order.
The order of the sorting is either the natural sorting order of the elements (if they implement java.lang.Comparable), or the order determined by a Comparator that you can give to the SortedSet.
By default the elements are iterated in ascending order, starting with the "smallest" and moving towards the "largest". But it is also possible to iterate the elements in descending order using the method TreeSet.descendingIterator().
The Java Collections API only has one implementation of the SortedSet interface - the java.util.TreeSet class. The java.util.concurrent package also has an implementation of this interface, but I will leave the concurrency utilities out of this trail.
Here are two examples of how to create a SortedSet:
SortedSet setA = new TreeSet();

Comparator comparator = new MyComparator();
SortedSet setB = new TreeSet(comparator);

More Details in the JavaDoc

There is actually a lot more you can do with a TreeSet that is not part of the SortedSet interface, like getting the highest and lowest element, splitting the set into subsets based on two values etc. Check out the JavaDoc if you need any of these more special features.

Java's Set Interface

The java.util.Set interface is a subtype of the java.util.Collection interface. It represents set of objects, meaning each element can only exists once in a Set.
Here is a list of the topics covered in this text:
  1. Set Implementations
  2. Adding and Accessing Elements
  3. Removing Elements
  4. Generic Sets
  5. More Details in the JavaDoc

Set Implementations

Being a Collection subtype all methods in the Collection interface are also available in the Set interface.
Since Set is an interface you need to instantiate a concrete implementation of the interface in order to use it. You can choose between the following Set implementations in the Java Collections API:
  • java.util.EnumSet
  • java.util.HashSet
  • java.util.LinkedHashSet
  • java.util.TreeSet
Each of these Set implementations behaves a little differently with respect to the order of the elements when iterating the Set, and the time (big O notation) it takes to insert and access elements in the sets.
HashSet is backed by a HashMap. It makes no guarantees about the sequence of the elements when you iterate them.
LinkedHashSet differs from HashSet by guaranteeing that the order of the elements during iteration is the same as the order they were inserted into the LinkedHashSet. Reinserting an element that is already in the LinkedHashSet does not change this order.
TreeSet also guarantees the order of the elements when iterated, but the order is the sorting order of the elements. In other words, the order in which the elements whould be sorted if you used a Collections.sort() on a List or array containing these elements. This order is determined either by their natural order (if they implement Comparable), or by a specific Comparator implementation.
There are also Set implementations in the java.util.concurrent package, but I will leave the concurrency utilities out of this tutorial.
Here are a few examples of how to create a Set instance:
Set setA = new EnumSet();
Set setB = new HashSet();
Set setC = new LinkedHashSet();
Set setD = new TreeSet();

Adding and Accessing Elements

To add elements to a Set you call its add() method. This method is inherited from the Collection interface. Here are a few examples:
Set setA = new HashSet();

setA.add("element 1");
setA.add("element 2");
setA.add("element 3");
The three add() calls add a String instance to the set.
When iterating the elements in the Set the order of the elements depends on what Set implementation you use, as mentioned earlier. Here is an iteration example:
Set setA = new HashSet();

setA.add("element 0");
setA.add("element 1");
setA.add("element 2");

//access via Iterator
Iterator iterator = setA.iterator();
while(iterator.hasNext(){
  String element = (String) iterator.next();
}


//access via new for-loop
for(Object object : setA) {
    String element = (String) object;
}

Removing Elements

You remove elements by calling the remove(Object o) method. There is no way to remove an object based on index in a Set, since the order of the elements depends on the Set implementation.

Generic Sets

By default you can put any Object into a Set, but from Java 5, Java Generics makes it possible to limit the types of object you can insert into a Set. Here is an example:
Set<MyObject> set = new HashSet<MyObject>();
This Set can now only have MyObject instances inserted into it. You can then access and iterate its elements without casting them. Here is how it looks:
for(MyObject anObject : set){
   //do someting to anObject...
}
For more information about Java Generics, see the Java Generics Tutorial.

More Details in the JavaDoc

There is a lot more you can do with a Set, but you will have to check out the JavaDoc for more details. This text focused on the two most common operations: Adding / removing elements, and iterating the elements.

Java's List Interface

The java.util.List interface is a subtype of the java.util.Collection interface. It represents an ordered list of objects, meaning you can access the elements of a List in a specific order, and by an index too. You can also add the same element more than once to a List.
Here is a list of the topics covered in this text:
  1. List Implementations
  2. Adding and Accessing Elements
  3. Removing Elements
  4. Generic Lists
  5. More Details in the JavaDoc

List Implementations

Being a Collection subtype all methods in the Collection interface are also available in the List interface.
Since List is an interface you need to instantiate a concrete implementation of the interface in order to use it. You can choose between the following List implementations in the Java Collections API:
  • java.util.ArrayList
  • java.util.LinkedList
  • java.util.Vector
  • java.util.Stack
There are also List implementations in the java.util.concurrent package, but I will leave the concurrency utilities out of this tutorial.
Here are a few examples of how to create a List instance:
List listA = new ArrayList();
List listB = new LinkedList();
List listC = new Vector();
List listD = new Stack();    

Adding and Accessing Elements

To add elements to a List you call its add() method. This method is inherited from the Collection interface. Here are a few examples:
List listA = new ArrayList();

listA.add("element 1");
listA.add("element 2");
listA.add("element 3");

listA.add(0, "element 0");
The first three add() calls add a String instance to the end of the list. The last add() call adds a String at index 0, meaning at the beginning of the list.
The order in which the elements are added to the List is stored, so you can access the elements in the same order. You can do so using either the get(int index) method, or via the Iterator returned by the iterator() method. Here is how:
List listA = new ArrayList();

listA.add("element 0");
listA.add("element 1");
listA.add("element 2");

//access via index
String element0 = listA.get(0);
String element1 = listA.get(1);
String element3 = listA.get(2);


//access via Iterator
Iterator iterator = listA.iterator();
while(iterator.hasNext(){
  String element = (String) iterator.next();
}


//access via new for-loop
for(Object object : listA) {
    String element = (String) object;
}
When iterating the list via its Iterator or via the for-loop (which also uses the Iterator behind the scene), the elements are iterated in the same sequence they are stored in the list.

Removing Elements

You can remove elements in two ways:
  1. remove(Object element)
  2. remove(int index)
remove(Object element) removes that element in the list, if it is present. All subsequent elements in the list are then moved up in the list. Their index thus decreases by 1.
remove(int index) removes the element at the given index. All subsequent elements in the list are then moved up in the list. Their index thus decreases by 1.

Generic Lists

By default you can put any Object into a List, but from Java 5, Java Generics makes it possible to limit the types of object you can insert into a List. Here is an example:
List<MyObject> list = new ArrayList<MyObject>();
This List can now only have MyObject instances inserted into it. You can then access and iterate its elements without casting them. Here is how it looks:
MyObject myObject = list.get(0);

for(MyObject anObject : list){
   //do someting to anObject...   
}
For more information about Java Generics, see the Java Generics Tutorial.

More Details in the JavaDoc

There is a lot more you can do with a List, but you will have to check out the JavaDoc for more details. This text focused on the two most common operations: Adding / removing elements, and iterating the elements.