Do you know what Java Collection is? It’s a useful framework that provides a set of methods, classes and interfaces to store and manage groups of objects.

Before the Java Collection framework was introduced, Java provided a lot of different classes each one with its own, very specific function.

Furthermore the methods and the way you used each class varied a lot.

It was obvious that a common architecture was necessary: the idea of Java Collection was born.

What is Java Collection?


It is a set of classes and methods, which allows to easily store and manipulate groups of objects.

Collections are different from arrays, because they not only have methods better suited to manage groups.

They’re also dynamic, so you don’t have to specify their size: collections can shrink and expand as you add or remove objects.

The Java Collection framework contains a lot of classes and interfaces, each one with their unique proprieties, but common base.

These are linked to each other through a hierachy that determines what characteristics some of them have in common, as shown below:

Java Collection Framework's hierarchy

Each branch inheritates all the methods of the point from which it originates, therefore branches that comes from a common point share some proprieties.

What is a framework in Java?


Frameworks are pieces of prewritten code which provides a foundation on which programmers can build their programs more easily.

Frameworks and libraries are different, but often confused.

The first is a mesh, whose components are linked together, leaving some white spots that you can fill out with your code.

Libraries, instead, are collections of mostly indipendent pieces of code that you can call when you need them.

Read Library vs. Framework for more

The Iterator Interface


Iterator allows you to cycle through a collection.

This interface contains 3 methods:

Methods
boolean hasNext( )
Returns true if there are more elements. Otherwise, returns false.
Object next( )
Returns the next element. If there is not a next element, it throws NoSuchElementException.
void remove( )
Removes the current element..
Example:

Output:

The Collection Interface


The Collection Interface contains the general methods that every class in the framework can use.

They are simple operations for managing groups of objects, such as add(), remove() and size().

It extends the Iterator interface, so it inheritates all its methods and characteristics.

Therefore you can get an Iterator object from a collection and cycle through its elements without knowing how many they are.

Here are the Collection Interface’s methods:

Methods
boolean add(Object o)
Inserts an object in the collection.
boolean remove(Object obj)
Removes an object from the collection.
boolean contains(Object obj)
Returns true if the invoking collection contains obj.
boolean addAll(Collection c)
Adds all c‘s elements to the invoking collection.
boolean removeAll(Collection c)
Removes all c‘s elements from the invoking collection.
boolean containsAll(Collection c)
Returns true if the invoking collection contains all elements of c.
void clear( )
Removes all elements.
boolean isEmpty()
Returns true if the invoking collection is empty.
Iterator iterator()
Returns the Iterator of the invoking collection.
boolean retainAll(Collection c)
Removes all elements from the invoking collection except those in c.
int size()
Gets the number of elements in the collection.
Object[ ] toArray( )
Creates an array which contains copies of the collection’s elements.
Object[ ] toArray(Object arr[ ])
Creates an array which contains copies of the collection’s elements whose type match that of arr.

The List Interface


The List Interface extends Collection and it determines the behaviour of collections that store sequences of elements.

Each element in the sequence can be accessed by its index, like it happens for arrays.

A list can also contain duplicates.

Methods
void add(int index, Object obj)
Inserts an object in the collection at the specified index, while all pre-existing elements at or beyond that point are shifted up.
boolean addAll(int index, Collection c)
Inserts all c‘s elements to the invoking collection at the specified index, while all pre-existing elements at or beyond that point are shifted up.
Object remove(int index)
Removes the object at the given index from the collection.
List subList(int start, int end)
Returns a List that contains the elements in the given range.
Object get(int index)
Gets the object at the given index.
int indexOf(Object obj)
Returns the index of the first instance of an object.
int lastIndexOf(Object obj)
Returns the index of the last instance of an object.
Object set(int index, Object obj)
Replace the object at the given index with a new one.
ListIterator listIterator()
Returns the ListIterator of the invoking collection.
ListIterator listIterator(int index)
Returns a ListIterator that start from the given index.

ArrayList


An ArrayList is basically a resizable array.

It implements the List Interface and it doesn’t introduce any new methods.

Example:

Output:

LinkedList


While arrays and ArrayLists store elements at contiguous location, LinkedLists don’t.

As you learned previously on this blog, each variable’s got its own memory space – let’s call it its cell.

In arrays, each element’s cell is right after the previous: the memeory space of one element touches the previous and the next.

In LinkedLists, each cell is separated from the others and they’re linked only by pointers.

At the end of each element’s cell there is a little amount of space reserved to a pointer that indicates the position of the next element.

LinkedList memorisation

Each element is at a random position and it’s linked to the others through pointers.

As you may have thought, this causes a greater memory requirement, because the computer has to allocate space for the pointers, too.

Furthermore, if you can remember, knowing the array’s first element’s address you could calculate the address of every other member at a given index.

However, you can’t do this with LinkedLists, because each one of its members can be everywhere in the the memory and their addresses are completely unknown to you and impossible to calculate.

Therefore the only option available to get an element is to go the first, get the address to the second, go there and repeat.

Fortunatelly, this is done by the framework, but it still comsumes a lot of computer resources.

Nevertheless, LinkedList makes insertion and deletion of elements fast and easy.

In ArrayLists, for example, when you add or remove an element at a certain index, the other ones are shifted up or down, but with LinkedLists all the computer has to do is change an address to point the new member.

Inserting an object in an ArrayList

ArrayList

Inserting an element in a LinkedList

LinkedList

LinkedList implements the List interface and the Deque interface we’re going to see later.

Example:

Output:

Vector


Vectors implements the List interface, too.

They aren’t much different from ArrayLists.

The three main differences in my opinion are:

  1. They can be used by only one thread.
  2. ArrayLists are faster.
  3. They can use both Enumeration and Iteration, while ArrayLists can only use the second one.

Stack


Stack is a class that implements the List interface based on the principle of last-in-first-out.

That means it provided methods that allow to get the latest added element, in particular through push and pop operations.

For example, when you stack some clothes, you put the latest on the top of the pile.

Last in First out

Then when you have to take those clothes one by one, the best idea is to start from the top, otherwise the pile collapse: the principle is the same.

It adds the following methods:

Methods
Object pop()
Returns and removes the top element of the stack.
Object peek()
Returns the top element of the stack, but it doesn’t remove it.
Object push(Object obj)
Pushes an element on the top of the stack.
boolean empty()
Returns true if the stack is empty.
int search(Object obj)
Returns the index of an object in the stack.
Example:

Output:

The Queue Interface


The Queue Interface extends the Collection Interface.

It follows the first-in-first-out principle, so it’s usually used to hold elements about to be processed.

Its name suits it very well: just like the first person of a queue is served first, the first element of a queue collection is removed first.

First in First out

When working with queue collections, you can only insert elements at the end and remove elements from the start.

The Queue Interface adds 5 methods:

Methods
boolean offer(object)
Adds an element to the queue without changing the collection’s size. It fails if there’s no more space left.
Object poll()
Removes and returns the first element of the queue. It returns null if the collection is empty.
Object remove()
Removes and returns the first element of the queue. It returns an error if the collection is empty.
Object element()
Returns the first element of the queue without removing it.
Object peek()
Returns the first element of the queue without removing it. It returns null if the collection is empty.

PriorityQueue


The PriorityQueue class implements the Queue interface.

Objects added to a PriorityQueue are sorted based on a default order or a custom Comparator.

It’s a queue whose elements need to be processed by their priority.

Example:

Output:

The Deque Interface


The Deque Interface extends the Queue Interface, but it supports insertion and deletion at both ends.

In fact its name is an acronym for double ended queue.

You can choose where to add or remove an object – start or end – by using some variants of existing methods. For example:

  • offer(Object o) adds an element to the end; offerFirst(Object o) adds it to the start;
  • poll() returns the first element; pollLast() returns the last element.

ArrayDeque


Just like ArrayList is a simple class that derives from the List interface without adding anything new, ArrayDeque is the class that makes the Deque Interface usable.

Remember: you can instanciate objects from interfaces; this is why the ArrayDeque class exists.

Example:

Output:

The Set Interface


The Set Interface contains only methods inherited from the Collection Interface.

However it adds a restriction: it can’t contain duplicate elements.

HashSet


HashSet is a simple class that implements the Set Interface.

That means that:

  • HashSet can’t contain duplicate elements;
  • It’s an unordered list, so it doesn’t maintain the order in which its elements are inserted.
Example:

Output:

LinkedHashSet


The LinkedHashSet class is identical to HashSet, apart from being ordered.

In fact it maintain the order in which its elements are inserted.

Example:

Output:

The SortedSet Interface


The SortedSet Interface is ordered, too.

However, instead of maintaining the order in which its elements are inserted, it sorts them based on a Comparator or a default order.

It also adds 6 methods:

Methods
Comparator comparator( )
Returns the invoking SortedSet’s comparator. If the natural ordering is used for this set, null is returned.
Object first( )
Gets the first element in the invoking SortedSet.
SortedSet headSet(Object end)
Returns a SortedSet containing those elements that come before end and that are contained in the invoking sorted set.
Object last( )
Gets the last element in the invoking SortedSet.
SortedSet subSet(Object start, Object end)
Returns a SortedSet that includes those elements between start and end.
SortedSet tailSet(Object start)
Returns a SortedSet that contains those elements that come after start and that are contained in the sorted set.

TreeSet


TreeSet implements SortedSet, but its defauld ordering system is Red-black tree.

This makes it very fast.

Example:

Output:

The Map Interface


A map in Java stores values assosiated to a key.

A key is similar to an index, but instead of being a number it’s an object of your choice.

Maps

In a map there can’t be duplicate keys, but there can be duplicate values.

The Map Interface contains a lot of methods, but these are the most important:

Methods
boolean containsKey(Object key)
Returns true if the map contains a mapping for the specified key.
void clear()
Removes all of the pairs from the map.
boolean containsValue(Object value)
Returns true if the map maps one or more keys to the specified value.
Set> entrySet()
Returns a Set that contains the mappings contained in the map.
void forEach(BiConsumer action)
Performs the given action for each entry in the map until all entries have been processed or the action throws an exception.
V get(Object key)
Returns the value to which the specified key is mapped.
V getOrDefault(Object key, V default)
Returns the value to which the specified key is mapped, or default if the map contains no mapping for the key.
V put(K key, V value)
Adds a pair key-value to the map.
boolean isEmpty()
Returns true if the map is empty.
Set keySet()
Returns a Set of the keys contained in the map.
void putAll(Map map)
Copies all the pairs from the given map to the invoking one.
V putIfAbsent(K key, V value)
Adds a pair if the given key isn’t already in use.
V remove(Object key)
Removes the mapping for a key from the map if it is present.
boolean remove(Object key, Object value)
Removes the given pair from the map.
V replace(K key, V value)
Replaces the entry for the specified key only if it is currently mapped to some value.
V replace(K key, V oldValue, V newValue)
Replaces the entry for the specified key only if it is currently mapped to the specified value.
int size()
Returns the number of pairs stored.
Collection values()
Returns a collection of all the values in the map.

HashMap


HashMap is the class that allows to use maps.

Yes, also HashMap is related to the Map Interface as ArrayList is to the List Interface and ArrayDeque is to the Deque Interface.

Example:

Output:

HashTable


HashTable is very similar to HashMap.

The main 3 differences are:

  • HashTables can only be used by one thread;
  • They don’t allow null keys or values, while HashMaps allow one null key and as much null values as you want;
  • HashTables sort and distinguish keys by their hash code, so objects that don’t contain the hashCode() method can’t be used.

The SortedMap Interface


The SortedMap Interface extends the Map Interface, but it sorts its elements using a default order or a Comparator.

To create sorted maps you must use the TreeMap class.

The SortedMap Interface adds the following methods:

Methods
Comparator comparator( )
Returns the invoking SortedMap’s comparator. If the natural ordering is used for this set, null is returned.
K firstKey( )
Gets the first key in the invoking SortedMap.
SortedMap headSet(K end)
Returns a SortedMap containing those pairs whose key come before end and that are contained in the invoking sorted map.
K lastKey( )
Gets the last key in the invoking SortedMap.
SortedMap subSet(K start, K end)
Returns a SortedMap that includes pairs whose key are between start and end.
SortedMap tailSet(K start)
Returns a SortedMap that contains those pairs whose key come after start and that are contained in the sorted map.
Example:

Output:

Comparator


We’ve seen that many classes and interfaces use custom comparators to sort elements.

A custom comparator is created by creating a class that implements the Comparator Interface.

This interface contains only one method to override:

You have to override this method to make it return a number than indicates if obj1 is less than (-1), equals to (0) or greater than (1) obj2.

Conclusion


If you’ve read the whole post, now you know almost every class and interface that makes the Java Collection Framework.

I wrote almost because there are some minor versions of some classes we’ve seen.

To sum up, the Collection framework is a set of interfaces, classes and methods that allows the programmer to easily manage groups of objects.

The main interfaces are Iterator and Collection, which is implemented by:

  • List: usually used for lists ordered by insertion and whose elements are managed through indexes;
  • Queue: follows the first-in-first-out principle;
  • Set: doesn’t allow duplicate elements.

These are very brief descriptions, so you should always read the full explanation in the sections above, if you need to remember the use of each interface.

Each of these three interface is implemented or extended by classes and other interfaces.

As always if you have any questions, ask them in a comment and if you liked the article, please share it.

Anyway, the post is finished, have a good day and we will see next week!

From Zephyro it’s all, Bye!

Categories: Learn Java

5 Comments

s shah · 1 May 2019 at 12:33 PM

thank you for such valuable content
this is the best article ive read this year. Serious gold
Highly appreciated content STRONGLY RECOMMENDED…!!!
More Programming Blogs UK, USA

    Zephyro · 1 May 2019 at 3:20 PM

    Thank you too. Consider sharing it: it would make my day!

imran ali · 30 October 2019 at 5:33 AM

Please keep sharing such great piece of article so we can get more knowledge about this type of topic.

Leave a Reply

%d bloggers like this: