I learned about Collections framework in Java in the first week itself. In fact this was the second topic that I picked up after learning the basics of the language.
Recently I was trying to teach Java to a beginner and I saw that the Collections framework is a bit hard to grasp for some people. And the reason that I think is the lack of knowledge about Java’s basic features like interface, classes and their relation. So, in this article, I will try to explain the Collections framework used in Java in addition to the interfaces, classes and generics.
In my experience, the computer science is a field that expects both practical and theoretical knowledge of the system you are working with. If any one of the thing is missing then it would make it hard to grasp and ultimately result in frustration and self-doubts. So whenever you are learning about any topic make sure you understand the theory well and translate the same in the code as well.
I would follow the similar approach with collections as well.
Let’s get started…
Table of Contents
What are Collections in JAVA?
Collections in JAVA is simply a framework that provides various data structures to store and retrieve a group of objects (collection).
It is a library of data structures which is optimized and highly flexible that can be used to store a group of objects and provides various ways to manipulate it.
For example – An ArrayList is a data structure that comes as a part of java.util
package. It provides multiple methods to interact with it like add, remove, get, etc… we will look at it in details later.
The reason it is so widely used is that for almost every practical application you need some sort of data structure. And if the collections framework wouldn’t have been there then the developer would have to develop it by him/her self.
It’s not easy to create optimized data structures. It is in itself a very tedious task. So most of the developer time would go into creating a data structure instead of doing the actual development. That’s why the collections framework is so important in Java. In fact, every language comes with some library that offers these data structures out-of-the-box.
It makes your task very easy and the best part – You don’t need to know the complex implementation that goes into creating optimized algorithms. All you have to do as a developer is to learn about the framework and learn to use them.
Collection Interface – Peek Under The Hood
This is the root interface in the Collection framework. Well, Collection also extends Iterable but that is only to allow the object to be the target of enhanced for statements. So, Collection interface is at the root.
Let’s take a peek into the Collection interface to see what all methods does it have.
Whoops… that’s a lot of methods.
And that is the point exactly. You get all this functionalities out-of-the-box when you choose to use Collection framework in Java.
Now, if you know about the basics of Java, you must be thinking that this is an interface. It only contains the method, a contract of some sort for the implementing class. So, who is implementing this interface to provide these functionality to us.
This question will take us further down the hierarchy.
Types Of Collection In Java
If you read more about grouping multiple objects and their behaviours in the world of Computer Science, you will end up creating three categories that would satisfy 95% of the use cases. And those three categories (interfaces) would be,
- List – this represents the order of the objects.
- Set – this group makes sure there are no duplicates
- Queue – Queues typically, but do not necessarily, order elements in a FIFO (first-in-first-out) manner. Among the exceptions are priority queues, which order elements according to a supplied comparator, or the elements’ natural ordering, and LIFO queues (or stacks) which order the elements LIFO (last-in-first-out).
Each of the above interface (list, set, queue) adds additional functionality on top of the Collection interface. These functionalities are related to that particular category. Now, things have started to become a tad bit clear. Now, we know what these interfaces are meant for. Next question would again be the same – if these are interfaces then where is the implementation?
And then once again we climb down the hierarchy to find out the implementations of these interfaces.
Just to express the importance of these interfaces, let me show you what a simple usage search in IntelliJ for List interface gives back. 10,459 usages inside JDK itself. This is irreplaceable. I’m sure there will be more :p
With that said, let’s checkout the most widely used List implementations.
ArrayList implements List Interface
This is perhaps the most widely used list implementation. It provides a resizable-array implementation of the List interface. That means you get the ability to grow the array dynamically. And it is very simple. Let me give you a very basic example of an ArrayList,
import java.util.ArrayList;
public class ArrayListExample {
public static void main(String[] args) {
var arrayList = new ArrayList();
arrayList.add("Varun");
arrayList.add("John");
arrayList.add(24);
arrayList.add(43);
arrayList.forEach(item -> System.out.println(item));
}
}
This is how easy it is to create an ArrayList and add items to it.
This brings us to another important topic of discussion and that is Generics.
Let’s take a little detour to understand generics a little bit.
Generics In Java
Although the above code works just fine. But there is a big problem. And the problem is that the Java compiler doesn’t know about the object types that the list should have. It means that every time you have to perform some operation, you will have to cast the object into the required type. And that is discouraged. Because this makes your code error-prone and difficult to read. You will not know what your list holds. And it will become messy pretty soon.
This is what I’m talking about,
if I have to add two numbers from the above list that are present in the index 2 and 3. Then below line will show error,
int sum = arrayList.get(2) + arrayList.get(3);
This is because compiler is not sure if the list contains integer values. Because we have not specified the list type in the beginning. So, if I have to perform the above operation that I would have to expliocitly tell the compiler that the object is an integer. And for that I would have to do it like this,
int sum = Integer.parseInt(String.valueOf(arrayList.get(2))) +
Integer.parseInt(String.valueOf(arrayList.get(3)));
So, in order to solve this problem, Java introduced Generics.
With generics, we can specify the type of objects the list should hold. It would be some object. It could be String or Integer or any custom object. But it will hold the objects of the same type. Let me show you the same example with Generics.
Here, I’ve specified the List type to the ArrayList<Integer>(). This means that this list can only hold Integer objects. Now, I cannot add a string value to this list. It will give me compile-time error.
import java.util.ArrayList;
public class ArrayListExample {
public static void main(String[] args) {
var arrayList = new ArrayList<Integer>();
arrayList.add(24);
arrayList.add(43);
arrayList.forEach(System.out::println);
int sum = arrayList.get(2) + arrayList.get(3);
System.out.println("Sum: " + sum);
}
}
I won’t go into details with Generics in this article, but to use the List, this is all you need to know for now.
Just like ArrayList there are different implementations for other interfaces as well. Some of these implementation are mentioned below,
- ArrayList
- Vector
- LinkedList
- HashSet
- HashMap
- TreeSet
- LinkedHashSet
Hierarchy of Collection Framework
You will find all the classes for collection framework in java.util package. This is how the interfaces and classes are linked with each other.
The Basics
Enough of the theory, as I said, I believe in getting hands dirty with code. It is time to write some code. Let’s learn a few basic stuff that will help you in the second part of this article where we will model a real-world problem.
How to use Collection Framework?
Glad you asked, as I said it is really very easy to get started with JAVA Collection. So, let’s quickly delve in.
For the time being, just go through the code and simply uncomment each line in the main method one-by-one and change the print list argument depending on the uncommented code.
For ex- if you uncomment the c.setExample();
then change the argument of the cc.printList(c.set);
. It will tell the print list method about the type of which is being thrown at it and will decide depending on the same.
Follow the CollectionExample.java class below…
The above example was of the Non-generics collection types. In Non-generics, you can insert any type of object. It doesn’t restrict you before adding anything to it.
However, this is not the right way to do it.
Eventually, you will end up writing lots of instanceof
 for checking the code which is pretty ugly and most probably faces lots of ClassCastException errors.
Always Always Always use Generics.
Now that you have a good understanding of the Collection Framework. You should do the following exercise,
Conclusion
This article was intended to educate you on the use of the collections framework in JAVA and how to get started with it. If you understood the concepts presented in this article then it’s time for the practicals. Shopping cart project is a good way to understand the use of Generics and different data structures in an object-oriented way.
Do checkout the following article,