Every Java developer should be aware of the importance of the Collection in Java. Needless to say, you can’t develop an application in Java without using the Collections. Even, Java community also assumes that Collection in Java is the most important topic after Java language basics and OOPs Concepts. Therefore, the Java Collections Framework becomes an essential component of the Java language that helps developers to manage data in an effective manner.
Moreover, Collection in Java provides the best possible algorithms for common operations such as search, sort, and insert, which can improve the performance of a Java application effectively. In this article, we are going to learn all the basic and advanced concepts of Collection in Java. Moreover, you must see many questions from this article while attending an interview for a Java developer.
What is a Collection In Java?
Collection in Java is an object which itself contains other objects without size limitations. The contained objects can be homogeneous, heterogeneous, unique or duplicate. Homogeneous objects are those who created from the same class. For example, Suppose we created some objects S1, S2, S3, S4 from the class Student. They will come under the category of homogeneous objects. On the other hand, if we create different objects from different classes, they will collectively be called heterogeneous objects. For example, if we create E1, E2, E3 from class Employee and S1, S2, S3 from class Student, then they will come under the category of heterogeneous objects.
What is the Java Collection Framework?
Like other frameworks, Java Collection Framework is also an API which is developed using a set of Java Classes and Interfaces. Moreover, Collection Framework provides us a mechanism to save and manipulate groups of objects with the help of classes & interfaces and methods under it. For example, String class in Java provides us various handy methods to manipulate strings. Similarly, Collection Framework provides us some readymade classes, interfaces and methods to manipulate a group of objects in the easiest way.
In sort, the Java Collections Framework is a set of classes and interfaces that provide a consistent and efficient way of working with collections of objects. The Interfaces provided by Collection Framework are Collection, List, Set, Map, Queue etc. All the classes under the Collection Framework implements any of these Interfaces directly or indirectly. Additionally, you may visit a separate article on enhancements of the Java Collection classes starting with JDK 1.0 and later versions.
How is the Collection better than Array in Java?
Sometimes this question is also asked in the interviews in another form, like ‘What is the difference between Collection and Arrays in Java?’. Undoubtedly, Collection in java comes after the Arrays, that means it must have easier approaches to solve the programming problems. Simply put, an Array is known for holding homogeneous objects, while the Collection for homogeneous as well as heterogeneous objects. It doesn’t mean that an array can’t hold heterogeneous objects. It is possible if we declare an array of java.lang.Object class (Object), which is the super class of any class in Java. Further, we can add any type of objects in that array.
1) No Limitations on the size of elements
When we define an array, we need to provide the size of the array. Further, if we try to insert more element than its size, we observe ArrayIndexOutOfBound error. On the other hand, we don’t need to provide the size of a Collection in java. Additionally, they adjust their size dynamically, when we try to insert additional elements into them. Hence, there are no limitations on the size of elements in the Collection.
2) Utility methods
Arrays store elements in the order of insertion and retrieve elements in the random order. If we want to retrieve the elements of arrays in sorted order (ascending/descending), or FIFO/LIFO (first in first out/last in first out) order, or only in sequential order, these features are not available. In order to make it possible, the developer needs to do additional coding. On the other hand, Collection in Java, offers us all these features such as sorting, searching, replacing, removing as the common utility methods without doing any additional coding.
Why to use a Collection in Java?
We use Collection in order to store, manipulate, and retrieve multiple objects under a single container just like a small in-memory database. We generally use a Collection in a method as a parameter and/or the return type. Apart from that Collection in Java, offers us various features such as:
1) An efficient & simple mechanism for organizing and retrieving data.
2) Manage and manipulate multiple objects as a single unit.
3) Implement commonly used algorithms, such as sorting, searching and filtering.
4) Provide a standard way of handling collections, making the code easy to read and maintain.
5) Reduce the effort needed to write the code by offering useful data structures and algorithms.
Additionally, collections can improve the performance of some operations and provide better memory management compared to manual implementation. Therefore, using collections can simplify the data storage, manipulation and performance of data in a Java program.
How does a Map differ from a Collection?
The Java Collection Framework is built on the basis of two main interfaces: Collection and Map. The Collection interface is used to represent a group of objects, known as elements, while the Map interface is used to represent a group of objects that hold a mapping in the form of keys and values. A single key-value pair is referred as an entry.
The Collection interface is a root interface for all types of collections and provides a set of common methods for handling collections, such as adding and removing elements. It has sub-interfaces like List and Set which have extra methods that are specific to their respective data structures.
Map, on the other hand, is not a sub-interface of Collection but is a separate interface in Java for representing key-value pairs. The map provides methods for storing and retrieving key-value pairs, where each key is unique and maps to a single value.
Therefore, technically the main difference between Map and Collection is that Collection is used for handling a group of elements and Map is used for handling entries (key-value pairs).
When to use Which Collection in Java?
When we want to store multiple objects without any limitation on the type and the size of objects, we should use a Collection in Java. This is because a Collection in Java stores multiple objects of same and/or different types with no limitation on the size. Let’s talk specifically about when to use which type of collection:
When to use a List?
Use a List Collection in java when you want to:
1) Maintain an order of elements
2) Allow duplicates
3) Retrieve elements based on their index
4) Iterate over the elements in a specific order
When to use a Set?
Use a Set Collection in java when you want to:
1) Eliminate duplicate elements
2) Store Unique Elements
3) ignore the order of elements
When to use a Queue?
Use a Queue Collection in java when you want to:
1) Store elements in a first in, first out (FIFO) order
2) Add elements to the end of the queue
3) Remove elements from the front of the queue
When to use a Deque?
Use a Deque Collection in java when you want to:
1) Store elements in a FIFO or LIFO order
2) Add elements to either end of the Deque
3) Remove elements from either end of the Deque
We can choose the type of a Collection in java that best fits our requirements depending on the properties that we actually need, such as order, duplicates, and retrieval operations.
When to use a Map in Java?
A Map in Java is used when we need to store and retrieve elements based on a unique key, rather than a group of elements. In other words, when we need to associate a unique key with a specific value, we should use a Map in Java.
A Map stores key-value pairs, where each key is unique and maps to a single value. The key can be used to retrieve the corresponding value. This makes Map an ideal data structure for situations where we need to store and retrieve elements based on a unique identifier.
For example, below are some of the use cases where we can use a Map:
1) Implementing a dictionary, where each word is a key and its definition is the corresponding value.
2) Implementing a cache, where each key is a resource identifier and the value is the cached resource.
3) Storing data in a key-value format, where each key represents a specific attribute and the value is the corresponding attribute value.
Generally, the Map interface is a popular data structure in Java and is used in various applications to store and retrieve elements based on a unique key.
How many types of classes/interfaces are there in Collection Framework?
To understand the Collection framework better and memorize it easily, we can divide the classes/interfaces into three groups based on their functionality.
1) Data Container Classes
Some of the classes/interfaces are generally used to store data, hence we can keep them in the group of Data Container classes. For example: List, Set, Map, ArrayList, LinkedList, HashSet, HashMap, TreeSet, TreeMap and their subclasses.
2) Data Retrieval Classes
Some of the classes/interfaces are used to traverse and retrieve the objects of a Collection such as, Iterator, ListIterator, Enumeration.
3) Utility Classes
There are two utility classes ‘Collections’ and ‘Arrays’ that are used to perform various operations on a Collection object directly.
What is the difference between Collections and Arrays classes?
Please note that we are going to discuss about the difference between two classes, which are Collections and Arrays, not the Collection framework and Arrays data structure. Collections (mind the character ‘s’ at the end) is a class under the Collection framework. Similarly, Arrays is also a class under the Collection framework. On the other hand, Collection (without the character ‘s’) is itself an interface under the Collection framework.
Collections class provides different static methods to perform manipulative operations on different types of collection objects. Arrays class provides different static methods to perform manipulative operations on array objects.
What are the Classes under the List Interface?
There are multiple implementations of the List interface:
ArrayList: ArrayList is an implementation of List interface that is supported by an array. It is dynamic in size, so elements can be added or removed as needed.
LinkedList: LinkedList is an implementation of List interface that uses a linked list data structure. It is more efficient for operations that involve inserting or removing elements in the middle of the list.
Vector: Vector is an implementation of List interface that is similar to ArrayList, but it is synchronized, meaning it is thread-safe.
Stack: Stack is an implementation of List interface that follows the last-in-first-out (LIFO) ordering, so the element that was added last is the first one to be removed.
CopyOnWriteArrayList: CopyOnWriteArrayList is an implementation of List interface that is designed for use in multi-threaded environments. It provides thread-safe access to the list and avoids the need for locking by copying the underlying array whenever an element is added or removed. We should use CopyOnWriteArrayList in a thread based environment where read operations are very frequent and update operations are rare. It also helps us to avoid ConcurrentModificationException.
Each of these implementations has its own advantages and use cases, and choosing the right one depends on the specific requirements of your application.
What are the Classes under the Set Interface?
There are multiple implementations of the Set interface:
HashSet: A HashSet uses a hash table for storage. It is an unordered collection of unique elements. In other words, it does not maintain the insertion order of elements and does not allow duplicate elements. Moreover, it provides constant-time performance for the basic operations such as add, remove, contains, and size, but the iteration order is not guaranteed to be in any particular order.
TreeSet: A TreeSet uses a tree structure for storage. It is a sorted set of unique elements. In other words, it maintains the elements in ascending order by default and does not allow duplicate elements. Moreover, it provides logarithmic time performance for the basic operations such as add, remove, and contains. However, the elements are stored in ascending order by default, but a custom comparator can be provided to sort the elements in any order.
LinkedHashSet: A LinkedHashSet uses a hash table and a linked list for storage. It is an ordered collection of unique elements. In simple words, it maintains the insertion order of elements and does not allow duplicate elements. This class provides all the benefits of a HashSet, with the additional benefit of preserving the order of the elements. However, it uses slightly more memory than a HashSet to maintain the order of elements.
EnumSet: EnumSet is a specialized Set implementation for use with enumeration types. It does not allow null Objects and throws NullPointerException if we do so.
In summary, HashSet is best for when you need fast access to elements, TreeSet is best for when you need elements to be sorted, and LinkedHashSet is best for when you need elements to be both sorted and ordered.
What are the Classes under the Map Interface?
HashMap: It uses a hash table for storage. It is an unordered collection of key-value pairs. Therefore, it does not maintain the insertion order of elements and does not allow duplicate keys.
Hashtable: It is an unordered collection of key-value pairs. Therefore, it does not maintain the insertion order of elements and does not allow duplicate keys. Hashtable is similar to HashMap, but Hashtable is synchronized, which means that it is thread-safe and can be safely used in a multi-threaded environment. However, synchronization comes at a performance cost, and Hashtable is generally slower than HashMap in a single-threaded environment.
Hashtable was part of the original Java collection framework and was introduced in Java 1.0. However, it is now considered to be an outdated class and it is recommended to use ‘java.util.concurrent.ConcurrentHashMap’ or other thread-safe collections instead.
LinkedHashMap: This class uses a hash table and linked list for storage. It is an ordered collection of key-value pairs. Therefore, it maintains the insertion order of elements and does not allow duplicate keys. However, it uses slightly more memory than a HashMap in order to maintain the order of elements.
TreeMap: It uses a tree structure for storage. It is a sorted collection of key-value pairs. Hence, it maintains the elements in ascending order by default of the keys and does not allow duplicate keys. Moreover, it is commonly used in Java when you need to store key-value pairs in a sorted order and perform operations such as finding the first or last key in the map, finding the largest or smallest key greater than or less than a specified key, etc. It is also useful when you need to retrieve a set of keys or values based on their position in the sorted order.
EnumMap: It is a specialized Map implementation for use with the enumeration types as keys. Moreover, the EnumMap class is intended to be more memory-efficient and faster than other Map implementations such as HashMap or TreeMap for keys of the enumeration type.
ConcurrentHashMap: It is a concurrent Map implementation that provides thread-safe access to its elements, allowing multiple threads to access and modify the map simultaneously. If you need a thread-safe Map, it is recommended to use ‘java.util.concurrent.ConcurrentHashMap’ instead of using synchronizedMap() method. ConcurrentHashMap provides more efficient and scalable thread-safety than synchronizedMap.
What is the role of Generics in the Collection Framework?
JDK 5 onward, Generics in Java play a crucial role in the Collection Framework by providing a way to parameterize the types of objects stored in a collection. Basically, it enables the type-safety of collections. Furthermore, it helps to prevent runtime type casting exceptions, reduces the need for explicit type casting, and also leads to better code readability. By using generics, the compiler can validate the type of the objects being added to a Collection. It also ensures that only objects of the correct type can be added to the Collection.
This means that when you create a collection, you can specify the type of objects that it should contain. For example, if you want to create a list of integer objects, you would use the following syntax using generics:
List<Integer> numbers = new ArrayList<>(); // Adding elements to the list numbers.add(1); numbers.add(2); numbers.add(3);
In this example, we are creating a List of Integer objects and adding three integers to the list. By specifying the type parameter <Integer>, the compiler can validate the type of the objects being added to the list, and ensure that only Integer objects are added. This eliminates the need for explicit type casting and reduces the chances of a runtime error.
What are the different ways to store the data in Java JVM?
Below is the list of ways to store data in Java JVM:
1) Variables: Using variable we can store a single value.
2) Classes: Using classes we can store a fixed number of multiple values of different types or same type with the help of different variables.
3) Arrays: Using Arrays we can store a fixed number of multiple values of the same type.
4) Collection: Using Collection we can store unlimited number of values of the same type or different types. In short, we should use a Collection in java when other ways (aforementioned) of storing values are not suitable.
Can an Array in Java store heterogeneous objects?
Yes, an array in java can hold heterogeneous objects. It is possible if we declare an array of java.lang.Object class (Object), which is the super class of any class in Java. Further, we can add any type of objects in that array.
When to use Arrays vs. Collection in Java?
If you know the size and the data type of elements, you can go with Arrays. Otherwise, go with a collection as a collection can store unlimited number of elements either of the same type or different types. Moreover, if you want to reduce coding effort, you can go with Collections, as it offers to use various utility methods. From the performance point of view, Array is better than a collection as utility methods take more time to execute.