Java Collections Framework | Iterator, Collection and List – Part 1

JCF is an acronym for Java Collections Framework. It is a framework which is like an architecture or a readymade system taking care of storage and manipulation of a group of objects. A framework is also an optional thing we use to make life easier.

At times you might be required to search, sort, insert, manipulate or delete big chunks of data. You can do all that with the help of Java Collections Framework.

what meme grandma for java collections framework

Well, let me explain grandma.

A collection is nothing but a single unit of objects, like a group. But when you look at the whole Java Collections Framework, it has got all sorts of interfaces, classes and algorithms in it to help you deal with your data. But Java collection is like just one one container that holds multiple items intact in one group.

In other words, you can say a Collection is a single entity or object taking care of a group of objects. These objects are known as its elements.

The API has interfaces that group these objects in the form of any of these following:

  1. List
  2. Queue
  3. Set

We are going to take a deeper look soon. Just chillax in your cozy reclining chair or bed, whatever.

Hierarchy of Java Collections Framework

It is the java.util package that has all the classes and interfaces we need for Java Collections Framework. Here’s a diagrammatic representation of the placement of interfaces and classes in Java Collections Framework.

hierarchy of java collection framework jcf

We will start from the top of the hierarchy of Java Collections Framework and make our way down. We will see all the interfaces first and then classes. So hang tight in there.

Iterable and Iterator Interface

At the topmost part of the hierarchy of Java Collections Framework we have Iterable Interface. To understand this we must first understand what iteration means. You have worked on loops before, right? So what was going on in it really? With the help of a loop, you were asking:

What’s next, printing it (or doing something), then asking again – what’s next, printing it (or doing something) until it eventually ran out.

So that’s what iteration is all about. You are leafing through elements one after the other, and then maybe trying to achieve something with the help of it.

Java has this one interface known as Iterable. It has a method called iterator() which returns another interface known as Iterator interface. So if any class implements iterable it will give you an Iterator interface.

Iterator interface, in turn, has three methods namely:

  • hasNext()
  • next()
  • remove()

These methods are pretty self-explanatory I guess with next() method returning the element and moving the cursor pointer to the next available element. hasNext() simply tells you whether or not a next element is available. Remove removes the last element retrieved.

You might want to cycle through a collection to see its elements and maybe modify them. You can do so with the help of an Iterator.

Cycling through a collection is nowadays being performed using for-each styled for loop or enhanced for loop. An example you will see soon enough.

NOTE: Iterator provides you the facility to iterate by moving in forward direction only. You can make use of ListIterator Interface to take care of bidirectional movement to modify a list. We will see that in a bit.

Collection Interface

The Collection Interface is the basis on which the Java Collections Framework is built. If you wish to define a class that defines collection, you must implement the Collection interface. Collection extends Iterable, so all the benefits of using Iterable (like foreach loop) can be raked in here as well.

There are tons of methods available in the Collection interface. You are going to make use of these at some point and hence I am gonna list them all down here:

  • add(Object e)
  • addAll(Collection c)
  • remove(Object e)
  • removeAll(Collection c)
  • retainAll(Collection c)
  • size()
  • clear()
  • contains(Object e)
  • containsAll(Collection c)
  • iterator()
  • toArray()
  • isEmpty()
  • equals(Object e)
  • hashCode()

Most of these methods are boolean methods, and they perform exactly what their names allude. Like add() would add an element to the Collection. size() will tell you the size etc.

As you can see, one of the methods named iterator() has been implemented from the iterable interface. You can use it to return an iterator. Then you could cycle through the collection and access each element at a time using this iterator object using its methods that we had seen above: next(), hasNext() and remove().

List Interface

A list is one of the crucial parts of Java Collections Framework. is an ordered collection. A list is also not so popularly known as a sequence. It allows duplicates as well. You can also have multiple null elements in the list.

Since you already know (by the Java Collections Framework hierarchical diagram) that list implements Collection all the methods of a Collection can be used here to get the job done. Apart from the methods mentioned above, there are some additional ones that come in handy when you are working with a list.

The following methods are available for usage in List interface. They will come in handy when you are dealing with a list.

  1. add(int index, Object e)
  2. addAll(int index, Collection c)
  3. get(int index)
  4. indexOf(Object e)
  5. lastIndexOf(Object e)
  6. listIterator()
  7. listIterator(int index)
  8. remove(int index)
  9. removeAll(Collection c)
  10. retainAll(Collection c)
  11. set(int index, Object e)
  12. subList(int fromIndex, int toIndex)
  13. toArray(T[] a)
  14. add(Object e)
  15. addAll(Collection c)
  16. remove(Object e)
  17. removeAll(Collection c)
  18. retainAll(Collection c)
  19. size()
  20. clear()
  21. contains(Object e)
  22. containsAll(Collection c)
  23. iterator()
  24. toArray()
  25. isEmpty()
  26. equals(Object e)
  27. hashCode()

I hope these methods are intelligible enough.

ListIterator Methods

listIterator() method of List gives you a result in the form ListIterator interface. The ListIterator interface, in turn, extends Iterator that we had seen earlier. It helps you to take care of bidirectional iteration. Here are the methods of ListIterator that you can use:

  • add(Object e)
  • hasNext()
  • hasPrevious()
  • next()
  • nextIndex()
  • previous()
  • previousIndex()
  • remove()
  • set(Object e)

ArrayList Class

One of the most important classes that implements List Interface in the Java Collections Framework is the ArrayList Class. As you already know we cannot instantiate an interface, so we will use one of its classes to instantiate it. Since List interface cannot be instantiated we will use a class that inherits it to instantiate it.

As you already know we cannot instantiate an interface, so we will use one of its classes to instantiate it. Since List interface cannot be instantiated we will use a class that inherits it to instantiate it.

As you can see in the above diagram ArrayList is one such class that implements the List interface, hence we will see it first.

ArrayList is one of the most popular classes used to store elements in an array in a dynamic form.

Java ArrayList can contain duplicate elements since it is a form of List only. You can randomly access any element here since it is an array form which works on the basis of indices. It is non-synchronized and maintains insertion order. It is a tad slow for manipulation as compared to others since it has deal with adjustment and stuff when an element is removed from it.

Here’s how ArrayList fits in the hierarchical chart:

ArrayList hierarchy in Java

So, as you can see ArrayList extends the AbstractList class which in turn extends AbstractCollection.

ArrayList Constructors and Methods

We have got three types of constructors here:

  • ArrayList()
  • ArrayList(Collection c)
  • ArrayList(int capacity)

The first one creates an empty ArrayList. The second one can directly take a Collection as a parameter. You can specify the initial capacity using the last one to create an empty ArrayList.

There are tons of methods available here:

  1. ensureCapacity(int minCapacity)
  2. removeRange()
  3. trimToSize()
  4. add(int index, Object e)
  5. addAll(int index, Collection c)
  6. get(int index)
  7. indexOf(Object e)
  8. lastIndexOf(Object e)
  9. listIterator()
  10. listIterator(int index)
  11. remove(int index)
  12. removeAll(Collection c)
  13. retainAll(Collection c)
  14. set(int index, Object e)
  15. subList(int fromIndex, int toIndex)
  16. toArray(T[] a)
  17. add(Object e)
  18. addAll(Collection c)
  19. remove(Object e)
  20. removeAll(Collection c)
  21. retainAll(Collection c)
  22. size()
  23. clear()
  24. contains(Object e)
  25. containsAll(Collection c)
  26. iterator()
  27. toArray()
  28. isEmpty()
  29. equals(Object e)
  30. hashCode()

Let’s see an example of ArrayList now.

Example of ArrayList in Java

As you might already know upcasting is fine in Java, and since interfaces cannot be instantiated but can be used for reference, so writing:

List l = new ArrayList();

would be as okay as writing:

ArrayList l = new ArrayList();

or

Collection l = new ArrayList();

or

Iterable l = new ArrayList();

for that to matter.

However, you wouldn’t be able to use the methods of that particular Interface or Class owing to the reference variable definition. So if you create a list using List l = new ArrayList(); you wouldn’t be able to access ArrayList method ensureCapacity() etc. So it is important to know what methods you are going to use and then refer it as per your need.

I am going to create a list now, and add some elements to it. Then I will try to remove two and see the new

ArrayList l = new ArrayList(3);
l.add("5");
l.add("Joe");
l.add("853");
l.add(1,"Roger");                    // Element placement using index 
l.add("44"); 
l.add("");                           //Null Element
l.add("5");                          //Duplicate element
System.out.println(l);               //Display ArrayList
System.out.println("The size of l is " + l.size()); //Size of ArrayList 
l.remove("Joe");   
l.remove(3);                        // Removing by index 
System.out.println(l);              // Displaying List Again
System.out.println("The size of l has become " + l.size()); //Size of ArrayList

If I try to run the above, I will get the following result:

[5, Roger, Joe, 853, 44, , 5]
The size of l is 7
[5, Roger, 853, , 5]
The size of l has become 5

As you can see, I tried to create an ArrayList of 3 elements. However, the capacity of an ArrayList object keeps increasing as you add elements. A list can have duplicate elements and NULL as well. So that’s what was demonstrated as well.

Use the get() method and you can obtain individual elements based on their indices or the element name. Like:

System.out.println(l.get(1));

Will give you Roger and so will:

System.out.println(l.get("Roger"));

Using Generics

Java provides us with the concept of Generics to take care of typecasting issues. It was introduced as part of J2SE 5 and is one of the most useful methods incorporated in Java Collections Framework to make your classes Type-Safe. Meaning if you use generics you don’t have to go about manually typecasting classes. Also, you can check for typecasting flaws during compile time itself. Isn’t that better?

You have the following benefits of using Generics in the Java Collections Framework:

  • Type-safety: Facilitates usage of only one type of object. Other objects won’t be allowed.
  • Eliminates need for Type Casting
  • Checks at Compile time

The syntax to use Generics is:

Class <T>

or

Interface <T>

where T should be replaced by the type you wish to use. Don’t forget those angular braces!

In the above example you could simply change the instantiation to appear like this:

ArrayList<String>l = new ArrayList<String>(3);

Here the type is String and should be put between ‘<‘ and ‘>’ signs.

How to Add Another List to an Existing List

If there was another list or if you had more than two lists and you wanted to add an entire list to your existing list, you could do so using addAll() method that takes a collection as a parameter.

I will just go ahead and create a second ArrayList and use the addAll() method to add the previous one to it:

ArrayList<String> al = new ArrayList<String>();

al.add("Nadal");

al.add("42");

al.addAll(l);

System.out.println(al);

If you run the above program you will get the following result:

[Nadal, 42, 5, Roger, Joe, 853, 44, , 5]

How to Cycle Through a List Like a Boss

Since one of the methods of ArrayList is called iterator(), you must have already guessed that it would allow you to iterate and enumerate easily. You can cycle through each element of your collection like a boss using the iterator and somehow it would feel better than cycling for real.

Let’s see how it’s done.

We will see the same example here and try to traverse through it using an iterator:

Iterator i = l.iterator();

while(i.hasNext()) {

System.out.println(i.next());

}

So here we are simply trying to call the iterator() method that returns Iterator Interface. We have provided a reference and used two of Iterator’s very own methods namely hasNext() and next().

If you augment the above code in our example, you will get the following result:

5
Roger
Joe
853
44

5

Cycling through a List Using For Each

Nowadays however, as discussed earlier, people often choose to iterate using Enhanced for each method, since you can get the job done in a single line.

Here’s how to do that:

for(String o: l) System.out.println(o);

If you print the above you will get the same result:

5
Roger
Joe
853
44

5

ListIterator’s Bidirectional Cycling

Since we are talking about Iterators here, let me get ListIterator out off my chest too. As discussed earlier, ListIterator comes into play when you have bidirectional cycling on the cards.

We will take the above example only and try to show how methods of ListIterator function:

ListIterator li = l.listIterator(); 

while(li.hasNext()) { 

System.out.println(li.next()); 

} 

while(li.hasPrevious()) { 

System.out.println(li.previous()); 

}

As you can see with the availability of hasPrevious() and previous() methods you could traverse back to the point you started your search from. If you run the above program you will get the following output:

5
Roger
Joe
853
44

5
5

44
853
Joe
Roger
5

How to Convert ArrayList into an Array and vice versa

What if you wanted to convert this ArrayList into an Array?

There’s a method called toArray() available here that you can use to do that:

Object u[] = l.toArray(); 

for(Object i: u) System.out.println(i);

Simply add the above code and you can print its array form as well. You can use a different for loop to print this, or alternatively, choose to use (Arrays.toString(u)) to print it in an Array format.

Okay now, what if you want to achieve the opposite? Like there’s an array you wish to convert to a collection?

That’s like the simplest thing ever!

You get a static method called asList() that returns a fixed size List in the Arrays class. It takes the array as a parameter.

An example would help. Let’s say you have a String array of vowels like this:

String vowels[] = {"a","e","i","o","u"};

Now you just have to make use of Arrays.asList() method and pass the vowels as a parameter for it to work. Since it returns a List, make the return type as List like this, and print it:

List<String>l = Arrays.asList(vowels);

System.out.println(l);

When you run the above you will get:

[a, e, i, o, u]

How to Make a List Read Only

There could be times when you would want your list to stay read only, so that no one should be able to edit it and disturb your peace. To make your list or collection for that to matter read only, Java Collections Framework provides you with static methods in Collection Class. These are all prefixed with unmodifiable.

For a list the following method does the job:

Collections.unmodifiableList(List);

We can have a look at one example:

List<String>l = new ArrayList<String>(); 

l.add("Crazy"); 
l.add("Insane"); 

List<String> unmod = Collections.unmodifiableList(l); 

unmod.add("Madding"); 

System.out.println(unmod);

Since it returns a List we need to create a reference variable of type List. We are trying to modify the list then using add method. If you run the above program you will get an UnsupportedOperationException.

Exception in thread "main" java.lang.UnsupportedOperationException 
at java.util.Collections$UnmodifiableCollection.add(Unknown Source) 
at collections.ArrayListExample.main(ArrayListExample.java:15)

Of course, you can handle it providing a much better message than the above.

How to Shuffle Elements in a List

Java Collections Framework provides a shuffling mechanism to help you randomize your list with maximum ease. The static method called shuffle() of Collections class is quite useful in shaking up your dices up good. It takes a list as a parameter.

Here’s how to do it:

List<String>l = new ArrayList<String>(); 

l.add("Crazy"); 
l.add("Insane"); 
l.add("Madding"); 

System.out.println(l); 
Collections.shuffle(l); 
System.out.println(l);

On running the program you will get the following:

[Crazy, Insane, Madding]
[Insane, Madding, Crazy]

I think there is nothing to explain here. You know what it did.

How to Rotate Elements in a List

In a similar manner, you could simply rotate your elements too, meaning forward the last element to show up at the first position, forcing others to move through like a belt. You could do so using the static method named rotate() of Collections. It takes two parameters, first one being the list, and the second one being the distance by which you want the rotation to happen.

Here an example would make you understand what really happens. I will use numbers to depict this so you know what’s really going on:

List<String>l = new ArrayList<String>();

l.add("3");
l.add("5"); 
l.add("7"); 
l.add("8");

System.out.println(l); 
Collections.rotate(l, 1);      //rotate by moving it just one place
System.out.println(l);

If you run the above you will get the following:

[3, 5, 7, 8]
[8, 3, 5, 7]

How to Sort Elements in a List

Let’s say you have random integers in your list and you want them all sorted in ascending and descending order. How do you achieve that?

Collections provide you with a static method called sort() that takes a list as parameters and returns a list as output. It takes care of sorting without troubling you a bit. So if we have a list of integers like this:

ArrayList <Integer> al = new ArrayList<Integer>(); 

al.add(7); 
al.add(5); 
al.add(9); 
al.add(5); 
al.add(8); 
al.add(10);
System.out.println(al);

We can make use of the Collections.sort() method to sort this list out. Simply add the following code and see the magic:

Collections.sort(al);
System.out.println(al);

If you run the above program you will get:

[7, 5, 9, 5, 8, 10]
 [5, 5, 7, 8, 9, 10]

Now since you have your result sorted in ascending order, wouldn’t the reverse of it be descending? Use Collections.reverse() to reverse the list and you have got yourself descending order as well.

Collections.reverse(al);
System.out.println(al);

Run the program and you will get:

[10, 9, 8, 7, 5, 5]

LinkedList Class

Moving on to the second type of List in our hierarchy. LinkedList Class makes use of doubly linked list to store elements. What is a doubly linked list, you ask?

what is a doubly linked list in java

In data structure, there is a kind of a list which is made up of nodes. Each node has three fields as shown in the diagram where the middle field holds the data and fields on either sides hold links references to previous and next nodes respectively. The starting and ending nodes are known as sentinel nodes or null. They are useful for traversal like we saw using rotate method earlier.

LinkedList extends AbstractSequentialList Class which in turn extends AbstractList. LinkedList also implements List and Deque interfaces both of whose methods you can use here.

Here’s a quick hierarchical diagram to represent where LinkedList Class stands:

LinkedList hierarchy in Java

LinkedList differs from ArrayList in the following ways:

  • Manipulation in LinkedList is quite fast since there is no shifting involved when an element is removed from the list.
  • LinkedList uses Doubly linked list to store elements, while ArrayList used dynamic array.
  • LinkedList can act as both list and queue while ArrayList could act as only list.
  • It is great for manipulating data while ArrayList was great for storing and accessing data.

Constructors and Methods of LinkedList

You get two types of constructors here:

  1. LinkedList()
  2. LinkedList(Collection c)

Here is a list of all the methods LinkedList can use:

  1. add(Object e)
  2. add(int index, Object e)
  3. addAll(Collection c)
  4. addAll(int index, Collection c)
  5. addFirst(Object e)
  6. addLast(Object e)
  7. clear()
  8. clone()
  9. contains(Object e)
  10. descendingIterator()
  11. element()
  12. get()
  13. getFirst()
  14. getLast()
  15. indexOf(Object e)
  16. lastIndexOf(Object e)
  17. listIterator(int index)
  18. offer(Object e)
  19. offerFirst(Object e)
  20. offerLast(Object e)
  21. peek()
  22. peekFirst()
  23. peekLast()
  24. poll()
  25. pollFirst()
  26. pollLast()
  27. pop()
  28. push(Object e)
  29. remove()
  30. remove(int index)
  31. remove(Object e)
  32. removeFirst()
  33. removeFirstOccurrence(Object e)
  34. removeLast()
  35. removeLastOccurrence(Object e)
  36. set(int index, Object e)
  37. size()
  38. toArray()
  39. toArray(T[] a)

Most of the methods here we have already seen in the examples for ArrayList Class. We will see some of them here. Let’s see an example quickly:

LinkedList <Integer> ll = new LinkedList<Integer>(); 

ll.add(7); 
ll.add(5); 
ll.add(9); 
ll.add(5); 
ll.add(8); 
ll.add(10); 
System.out.println(ll); 
ll.push(4); 
System.out.println(ll); 
ll.pop(); 
System.out.println(ll); 
ll.removeFirst(); 
System.out.println(ll); 
ll.removeLast(); 
System.out.println(ll);

If you run the above program you will get the following result:

[7, 5, 9, 5, 8, 10]
[4, 7, 5, 9, 5, 8, 10]
[7, 5, 9, 5, 8, 10]
[5, 9, 5, 8, 10]
[5, 9, 5, 8]

As you can see push and pop will simply push the given element on the stack or remove it.

Iterating Through LinkedList in Reverse Order

There’s this method provided in LinkedList called descendingIterator() which returns an Iterator object in reverse order. So it would just print a reversed form of whatever your list might contain.

We will see an example to make things clearer:

LinkedList <Integer> ll = new LinkedList<Integer>(); 
ll.add(7); 
ll.add(5); 
ll.add(9); 
ll.add(5); 
ll.add(8); 
ll.add(10); 
Iterator itr = ll.descendingIterator(); 
while(itr.hasNext()){ 
System.out.println(itr.next()); 
}

You run the above program you will get:

10
8
5
9
5
7

Our topic is far from getting over. Let’s take a badly needed break here.

In Part 2 of this section we will see Queue.

Scottshak

Poet. Author. Blogger. Screenwriter. Director. Editor. Software Engineer. Author of "Songs of a Ruin" and proud owner of four websites and two production houses. Also, one of the geekiest Test Automation Engineers based in Ahmedabad.

You may also like...

3 Responses

  1. June 28, 2017

    […] in Java chapter is an immediate successor of Java Collections Framework that we had seen earlier. Make sure you have completely understood List before proceeding to learn […]

  2. June 29, 2017

    […] you are coming here for the first time I advise you to check out Java Collections Framework – List and Queue to keep things in order which are like the part 1 and part 2 of […]

  3. June 30, 2017

    […] taking this as a separate topic. Although we are going to see it in a similar style just as we saw Java Collections Framework in the […]

Leave a Reply