List interface:

1. List is child interface of Collection.
2. If we want to represent a group of individual objects as a single entity where duplicate are allowed and insertion order must be preserved then we should go for List.
3. we can preserve insertion order via index and we can differentiate duplicate objects by using index.
Hence index will play important role in List.

List interface defines the following specific methods

void add(int index, Object o)
boolean addAll(int index, Collection c)
Object get(int index)
Object remove(int index)
Object set(int index, Object newObj)
: to replace the element present at specified index with provided Object and return old Object
int indexOf(Object o)
: returns index of first occurence of 'o'
int lasIndexOf(object o)
: returns last index of first occurence of 'o'
ListIterator listIterator();
ListDiagram

ArrayList:

1. It is one of the implementation class of List Interface and present Since JDK 1.2.
2. ArrayList implements a data structure called growable array / resizable array.
3. ArrayList maintains insertion order and accepts null and duplicate data.
4. Heterogeneous objects are allowed (except TreeSet and TreeMap everywhere heterogeneous Objects are allowed).
4. Null insertions are possible
5. It internally stores the data in the form of Array of type Object.
6. Initial capacity of ArrayList is 10.
7. Incremental capacity is (current capacity x 3/2) +1
8. ArrayList uses Continuous Memory.

ArrayList

There are 3 overloaded constructors present in case of ArrayList.

public ArrayList()

creates an empty ArrayList object with default initial capacity 10. Once ArrayList reaches its maximum capacity then a new ArrayList Object is created with new capacity is (current capacity X 3/2) + 1

public ArrayList(int initialCapacity)

creates an empty ArrayList Object with specified initial capacity.

public ArrayList(Collection<? extends E> c)

creates equivalent ArrayList Object for given Collection.

Usually, we can use Collections to hold and transfer Objects from one location to another location(container) to provide support for this requirement every Collections class by default implements

  • Cloneable interface
  • Serializable interface

ArrayList and Vector classes implements RandomAccess interface so that any random element we can access in same speed.

RandomAccess:

RandomAccess present in java.util package and it doesn’t contain any methods. It is a marker interface, where the required ability will be provided automatically by the JVM.


ArrayList l1 = new ArrayList();
LinkedList l2 = new LinkedList();
System.out.println(l1instanceof Serializable); //true
System.out.println(l2instanceof Cloneable); //true
System.out.println(l1instanceof RandomAccess); //true
System.out.println(l2instanceof RandomAccess); //false

//ArrayList Program
import java.util.ArrayList;
class ArrayListDemo{
    public static void main(String[] args){
        ArrayList<Stringal = new ArrayList<String>();
        al.add("Java");
        al.add("JDBC");
        al.add("Servlets");
        al .add(null);
        System.out.println(al); //[Java, JDBC, Servlets, null]
        al.remove(2);
        System.out.println(al); //[Java, JDBC, null]
        al.add(2"Spring");
        al.add("Hibernate");
        System.out.println(al); //[Java, JDBC, Spring, null, Hibernate]
    }
}

Output: [Java, JDBC, Servlets, null]
[Java, JDBC, null]
[Java, JDBC, Spring, null, Hibernate]

Situations to use ArrayList:

ArrayList is good for data retrieval & search operation. Because time taken to search any data in entire List is same. (because ArrayList implements RandomAccess interface)

Situations not to use ArrayList:

It we try to add the data in between the list then all the existing data gets shifted to next position, so because of this shift operation the performance becomes slow.

How to get synchronized version of ArrayList object???

By default, ArrayList is non synchronized but we can get synchronized version of ArrayList object by using synchronized method of Collections class.

public static List synchronizedList(List l)

For Example

ArrayList l = new ArrayList();
List l1 = Collections.synchronizedList(l);

Now, l is non synchronized
l1 is synchronized
Similarly, we can get synchronized version of Set and Map objects by using the following methods of Collections class.

public static Set synchronizedSet(Set l)
public static Map synchronizedMap(Map l)

LinkedList:

1. LinkedList is one of the implementation class of List Interface and presence Since JDK 1.2.
2. The internal data structure is Doubly LinkedList.
3. Heterogeneous Objects are allowed.
4. Duplicates are allowed.
5. Insertion order is preserved.
6. Null insertion possible.
7. LinkedList stores the data in the form of Nodes. Where in every node is connected to next and its previous node.
8. The first node does not have previous node information and last node does not have next node information.
9. LinkedList implements marker interface like Serializable, Cloneable but not RandomAccess.
10. Good for modification / addition / removal.
11. No initial capacity / no incremental capacity.

LinkedListDiagram

LinkedList has only 2 Constructors.

public LinkedList()

creates an empty LinkedList object

public LinkedList(Collection<? extends E> c)

creates an equivalent LinkedList object for given Collection.

LinkedList class specific methods:

Usually, we can use LinkedList to develop Stacks and Queues.
To provide support for this requirement LinkedList class defines the following specific methods.

void addFirst(Object o)
void addLast(Object o)
Object getFirst()
Object getLast()
Object removeFirst()
Object removeLast()


//Program on LinkedList
import java.util.*;
class LinkedListDemo{
    public static void main(String[] args){
        LinkedList<Stringll = new LinkedList<String>();
        ll.add("Java");
        ll.add("JDBC");
        ll .add(null);
        ll.add("Java");
        ll.set(0"C");
        ll.add(0"Java");
        ll.removeLast();
        ll.add("Hibernate");
        System.out.println(ll); //[Java, C, JDBC, null, Hibernate]
    }
}

Situations to use LinkedList :

LinkedList doesn’t have any shift operation, hence it is suitable for insertion or removal of data in between.

Situations not to use LinkedList :

1. LinkedList is not suitable for any search / retrieval operation.
2. LinkedList are not good for addition / removal because the control has to start / traverse through first node.

Vector:

1. It is one of the implementation class of List Interface and present Since JDK 1.0 [legacy class].
2. Vector implements a data structure called growable array / resizable array.
3. Vector maintains insertion order and accepts null and duplicate data.
4. Heterogeneous objects are allowed.
5. Vector implements marker interfaces like:

  • Cloneable
  • Serializable
  • RandomAccess
6. Every method is present in the Vector is synchronized and hence Vector Object is Thread safe.
7. It internally stores the data in the form of Array of type Object.
8. Initial capacity of Vector is 10.
9. Incremental capacity is current capacity x 2.

There are 4 overloaded constructors present in case of Vector.

public Vector()

creates an empty Vector Object with default initial capacity 10. Once vector reaches maximum capacity then the new Vector object will be created with new capacity = currentCapacity x 2

public Vector(int initialCapacity)

creates an empty Vector Object with a specified initial capacity.

public Vector(int initialCapacity, int capacityIncrement)
public Vector(Collection<? extends E> c)

creates an equivalent Vector object for a given Collection. This constructor meant for inter conversion between objects.

Vector class specific methods:

addElement(Object o)
removeElement(Object o)
removeElementAt(int index)
removeAllElements()

//Program on Vector
import java.util.*;
class VectorDemo{
    public static void main(String[] args){
        Vector v = new Vector();
        System.out.println(v.capacity()); //10
        for(int i = 1; i <= 10; i++){
            v.addElement(i);
        }
        System.out.println(v.capacity()); //10
        v.addElement("A");
        System.out.println(v.capacity()); //20
        System.out.println(v); //[1, 2, 3, .... , 10, A]
    }
}
  • Vector also has shift operation if we try to add the data in between.
  • Vector is good for data retrieval & search operation. Because time taken to search any data in entire List is same.

To add Objects:

add(Object o) -----> Collection
add(int index, Object o) -----> List
addElement(Object o) -----> Vector

To remove Objects:

remove(Object o) -----> Collection
removeElement(Object o) -----> Vector
remove(int index) -----> List
removeElementAt(int index) -----> Vector
removeAllElements() -----> Vector
clear() -----> Collection

To get Objects:


Object get(int index) -----> List
Object elementAt(int index)-----> Vector
Object firstElement() -----> Vector
Object lastElement() -----> Vector

Other methods:

int size()
int capacity()
Enumeration elements()

Stack:

1. It is the child class of Vector.
2. It is a specially designed class for Last In First Out order (LIFO).

StackDiagram

There are 1 overloaded constructor present in case of Stack.

public Stack()

Stack class specific methods:

Object push(Object o) : to insert an object into the Stack.
Object pop() : to remove and return top of the Stack.
Object peek() : to return top of the Stack without removal.
boolean empty() : returns true if the Stack is empty.
int search(Object o) : returns offset if the element is available otherwise returns -1.


//Program on Stack
import java.util.*;
class StackDemo{
    public static void main(String[] args){
        Stack<Strings = new Stack<String>();
        s.push("Java");
        s.push("Spring");
        s.push("Hibernate");
        System.out.println(s); //[Java, Spring, Hibernate]
        System.out.println(s.search("Java")); //3
        System.out.println(s.search("Servlets")); //-1
    }
}

Cursors in java:

If we want to get objects one by one from a Collection then we should go for cursor.

There are three cursors in java
1. Enumeration
2. Iterator
3. ListIterator

Enumeration:

We can use Enumeration to get objects one by one from legacy Collection object.
we can create Enumeration object by using element() method of Vector class.

public Enumeration elements();
eg: Enumeration e = v.elements();

v means Vector object.

Enumeration specific methods:

public boolean hasMoreElements();
public Object nextElement();

//Program on Enumeration
import java.util.*;
class EnumerationDemo{
    public static void main(String[] args){
        Vector<Integerv = new Vector<Integer>();
        for(int i = 0; i <= 10; i++){
            v.addElement(i);
        }
        System.out.println(v);
        Enumeration<Integere = v.elements();
        while(e.hasMoreElements()){
            Integer I = (Integer)e.nextElement();
            if(I % 2 == 0){
                System.out.println(I + " " );
            }
        }
        System.out.println(v);
    }
}

Output:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
0
2
4
6
8
10
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Limitations of Enumeration:

1. We can apply Enumeration concept only for legacy classes and it is not a universal cursor.
2. By using Enumeration we can get only read access and we can’t perform remove operation.

To overcome above limitations, we should go for Iterator.

Iterator:

1. We can apply Iterator concept for any Collection object and hence it is universal cursor.
2. By using Iterator, we can perform both read and remove operations. we can create Iterator object by using iterator() method of Collection interface.

public Iterator iterator();
eg: Iterator itr = c.iterator();

Iterator specific methods:

public boolean hasNext()
public Object next()public void remove()




//Program using Iterator
import java.util.*;
class IteratorDemo{
    public static void main(String[] args){
        ArrayList<Integeral = new ArrayList<Integer>();
        for(int i = 0; i <= 10; i++){
            al.add(i);
        }
        System.out.println(al);
        Iterator itr = al.iterator();
        while(itr.hasNext()){
            Integer I = (Integer)itr.next();
            if(I % 2 == 0){
                System.out.print(I + " " );
            }
            else{
                itr.remove();
            }
        }
        System.out.println(itr);
    }
}

Output:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
0 2 4 6 8 10
java.util.ArrayList$Itr@5d22bbb7

Limitations of Iterator:

1. By using Enumeration and Iterator we can always move only towards forward direction and can’t move backward direction. These are single direction cursors but not bidirectional cursor.
2. By using Iterator, we can perform only read and remove operations and we can’t perform replacement and addition of new objects.
To overcome above limitations, we should go for ListIterator.

ListIterator:

1. By using ListIterator we can move either to the forward direction or backward direction and hence it is bidirectional cursor.
2. By using ListIterator we can perform replacement and addition of new Objects in addition to read and remove operations.

we can create ListIterator by using listIteraor() method of ListIterator interface.

public ListIterator listIterator()
ListIterator ltr = l.listIterator();

ListIterator is the child interface of Iterator and hence all methods present in Iterator by default available to the ListIterator.

ListIterator

ListIterator specific methods:
ListIterator defines following 9 methods:

//Forward operations
public boolean hasNext()
public Object next()
public int nextIndex()

//Backward operations
public boolean hasPrevious()
public Object Previous()
public int PreviousIndex()

//Extra operations
public void remove()
public void add(Object o)
public void set(Object o)



import java.util.*;
class ListIterator{
    public static void main(String[] args){
        LinkedList<Stringll = new LinkedList<String>();
        ll.add("C");
        ll.add("C++");
        ll.add("Servlets");
        ll.add("JDBC");
        System.out.println(ll); //[C, C++, Servlets, JDBC]
        ListIterator<Stringltr = ll.listIterator();
        while(ltr.hasNext()){
            String s = (String)ltr.next();
            if(s.equals("C++")){
                ltr.remove();
            }
            else if(s.equals("Servlets")){
                ltr.add("Spring");
            }
            else if(s.equals("JDBC")){
                ltr.set("Hibernate");
            }
        }
        System.out.println(ll); //[C, C++, Servlets, JDBC]
    }
}

Output: [C, C++, Servlets, JDBC]
[C, Servlets, Spring, Hibernate]

The most powerful cursor is ListIterator but its limitation is it is applicable to List Objects.

Comparison table of three cursors:

property Enumeration Iterator ListIterator
Where we can apply? Only for Legacy classes for any Collection object only for List Objects
Is it legacy? yes(1.0) no(1.2V) no(1.2V)
Movement Single direction (only for forward direction) Single direction (only for forward direction) Bidirectional
Allowed operations How we can get? Only read By using elements() of Vector class read/remove By using iterator() of Collection interface read/remove/replace/add By using listIterator() of List interface
methods 2 methods 3 methods 2 methods 3 methods 9 methods

Internal implementation of cursors:

import java.util.*;
class CursorsDemo{
    public static void main(String[] args){
        Vector<Stringv = new Vector<String>();
        Enumeration<Stringe = v.elements();
        Iterator<Stringitr = v.iterator();
        ListIterator<Stringlitr = v.listIterator();
        System.out.println(e.getClass().getName());
        System.out.println(itr.getClass().getName());
        System.out.println(litr.getClass().getName());
    }
}

Output:
java.util.Vector$1
java.util.Vector$Itr
java.util.Vector$ListItr