For all data manipulation activities, including data storage, searching, sorting, insertion, deletion, and updating, Java Collections are one-stop shops. A Java collection framework provides a range of Interfaces and Classes, and a Java collection responds as a single object.
You now have all the information you need to understand Java Collections. When working with real-time data, Java Collections are helpful. It's crucial to have a fundamental idea of how to become a software developer after having a firm grasp of Java Collections.
So let's explore the plethora of relevant Java Collections questions in depth.
A set of classes and an interface for managing data in the form of objects are part of the Collection Framework. It accomplishes this by offering interfaces like List, Queue, and Set as well as classes like ArrayList, Vector, Stack, and HashSet. Prior to the introduction of Collection Framework, Arrays, Vectors, and Hash Tables were the common methods for aggregating Java objects (or collections) (or JDK 1.2). There was no unified interface for all of these collections. Because of this, there is no correlation between the collections, even if they all share the same fundamental goal. Additionally, users have trouble remembering all of the various constructors, methods, and syntax that are included in each collection class.
When it comes to storing object references and handling data, arrays and collections are similar, but they also have some key differences. The following are the main distinctions between an array and a collection:
• A user cannot change the length of an array during runtime or according to their needs because arrays have a fixed size. However, with collections, the size can be changed dynamically as necessary.
• Arrays can only store homogenous or similar type objects; collections can store heterogeneous objects.
• Collections, as opposed to Arrays, can offer pre-made answers to user needs including sorting, searching, and other similar tasks.
• When it comes to memory, collections are preferred over arrays.
The Collection and Map interfaces are the most frequently used interfaces that the Java Collection Framework implements (java.util.Map). A list of Collection Framework interfaces is shown below:
🚀 The collection framework's primary interface is the iterable interface. The iterable interface is expanded by the collection interface. As a result, all classes and interfaces by default implement this interface. This interface's main objective is to give the collections an iterator. As a result, this interface only has one abstract method.
🚀 The classes that make up the collection framework implement this interface, which extends the iterable interface. All of the fundamental data collection techniques, such as adding, removing, clearing, and so on, are included in this interface. All of these methods are part of this interface because, regardless of how they are implemented, they are used by all classes. It also guarantees that method names are consistent across all collections by include these methods in the interface. We can conclude that this interface serves as the building block for collection class implementation.
🚀 Interface for lists: The interface for lists is a subinterface of the interface for collections. List data, which may be used to store every item in an ordered collection, is the focus of this interface. Additionally, duplicate data is made possible by this. This list interface is implemented by a number of classes, including ArrayList, Vector, Stack, and others. Any of these classes can be used to create a list object because they all implement the list.
🚀 Queue Interface: A queue interface follows the FIFO (First In First Out) order of a real-world queue line. All items where the order of the elements matters are stored using this interface. For instance, when we go shopping, we are issued bills based on who arrives first. As a result, the bill is given to the individual who made the first request first. There are various classes, including ArrayDeque, Deque, and PriorityQueue. Because they all implement the queue, we can create a queue object using any of these subclasses.
🚀 Data structure of the Deque Interface is slightly different from that of the Queue Interface. A deque, also referred to as a double-ended queue, is a type of data structure that enables addition and deletion of components from both ends. The queue interface is expanded by this interface. The class ArrayDeque implements this interface. This class implements the deque, thus we can use it to create a deque object.
🚀 Set Interface: A set is a group of objects that cannot store duplicate values and is not sorted. When we only want to maintain items that are unique and avoid duplication of stuff, we use this collection. This set interface is implemented by a number of classes, such as HashSet, TreeSet, LinkedHashSet, and others. We can create a set object using any of these classes because they all implement the set.
🚀 Key-value pairs are stored in a Map (java.util.Map), a type of element storage. The Map interface does not implement the Collection interface. Duplicate elements are permitted, but it can only have one unique key. The two interfaces that implement Map in Java are the Map interface and the Sorted Map interface.
API that is consistent: The API is composed of a core set of interfaces, such as Collection, Set, List, or Map, and any classes that implement these interfaces (such as ArrayList, LinkedList, Vector, and so on) share a set of methods.
Reduces programming effort: Instead of thinking about the Collection's design, a programmer may concentrate on how to use it in his programme. As a result, the core concept of object-oriented programming—abstraction—has been effectively used.
The List and Set add to the collection interface. However, there are several differences between the two, which are listed below.
• While Sets contain unique items, Lists may contain duplicate elements.
• In contrast to the unordered Set, which loses its insertion order, the List is an ordered collection that maintains its insertion order.
• The Vector class is the only legacy class for the List interface; there are none for the Set interface.
• The Set interface only permits one null value, but the List interface permits an infinite number.
ArrayList | LinkedList |
---|---|
The elements of this class are kept in a dynamic array. Generics have made it possible for this class to now handle the storage of any kind of objects. | A doubly-linked list is used to store the items of this class. Similar to the ArrayList, this class enables the storage of any kind of object. |
An ArrayList requires more time to manipulate because of the internal implementation. The array is internally searched and the memory bits are altered when an element is removed. | A doubly-linked list takes less time to manipulate than an ArrayList since it is incapable of changing memory bits. The reference link is updated upon the list's exploration. |
This class is more helpful when the programme has to store and access data. | This class is more helpful when the application includes data manipulation. |
ArrayList | Vector |
---|---|
The ArrayList doesn't need any synchronisation. | Vector is synchronized. |
When utilising an ArrayList, the array's size is raised by 50%. | The vector's size is increased by doubling the size of the array. |
ArrayList is not thread-safe since it is not synchronised. | A vector list is thread-safe because every procedure is synchronised within it. |
The Collection framework in Java uses iterators to get elements one by one. It is comparable to any collection object. The iterator has the ability to read and delete data. All Collection foundation interfaces, including Set, List, Queue, and Deque, as well as all Map interface implemented classes, must iterate components using an Iterator. Throughout the collection framework, there is just one cursor available: the iterator.
ListIterator can only be used by classes that implement List collections, such as array lists and linked lists. It has the capacity to iterate both ways. Enumerating List elements requires the usage of a ListIterator. This cursor has more methods and capabilities than the iterator.
Iterator | ListIterator |
---|---|
only has the capacity to advance through Collection components. | can navigate backwards and forwards through components in a collection. |
Iterators cannot be used to retrieve indexes. | When traversing a List, it contains methods like next Index() and previous Index() that can be used to obtain element indexes at any time (). |
It facilitates navigation over Maps, Lists, and Sets. | Only List can be traversed; not the other two. |
It would be incorrect to demand a public clone method from every Collection implementation, including all of the ones offered by the JDK. What does it mean, for instance, to copy a Collection that is supported by a terabyte-sized SQL database? Should the business order a new disc farm as a result of the method call? The same may be said for serializable.
It's much more flexible and less likely to cause errors to let the client choose the type of Collection they want, create an empty Collection of that type, and then use the addAll method to copy the elements of the original collection into the new one if they don't already know what type the collection is.
We are able to add null elements to a HashSet but not a TreeSet. Because TreeSet compares using the compareTo() function, which throws a NullPointerException when it encounters a null element, this is the case.
If you change the value in the properties file, you don't need to recompile the Java class. The application is therefore easy to manage. It is used to keep track of data that must be regularly updated. Take the example below into consideration.
import java.util.*; import java.io.*; public class Test { public static void main(String[] args)throws Exception{ FileReader reader=new FileReader("db.properties"); Properties p=new Properties(); p.load(reader); System.out.println(p.getProperty("user")); System.out.println(p.getProperty("password")); } }
HashSet: Searching, adding, and removing objects all take the same amount of time. TreeSet is slower than HashSet. HashSet is implemented with a hash table.
TreeSet has a higher search, insert, and delete time than HashSet, which is O(Log n). On the other hand, TreeSet maintains data order. There are also support for additional methods like higher(), floor(), and ceiling(), which return the element with the lowest higher order. These operations are not implemented by HashSet since they are O(Log n) in TreeSet. Using a Self-Balancing Binary Search Tree, TreeSet is implemented (Red Black Tree). Java's TreeMap is the engine behind TreeSet.
• The components of a hash set are not ordered. The Comparable or Comparator methods are used to establish the Sorted order in which the Java TreeSet class keeps its objects. By default, TreeSet components are ordered in ascending order. It provides techniques for working with ordered sets, including first(), last(), headSet(), tailSet(), and other similar techniques.
• Null objects are accepted in hash sets. TreeSet does not allow null objects, and if one is found, a NullPointerException is raised. This is because TreeSet compares keys using the compareTo() function, which raises a Java.lang exception. NullPointerException.
Which one prefer:
• Unique elements are not needed; sorted unique elements are. TreeSet always produces a sorted list in ascending order.
• Compared to HashSet, TreeSet has a higher level of locality. In contrast to HashSet, which distributes the entries across memory regardless of the keys to which they are linked, TreeSet puts two items in the same data structure and consequently in memory if they are in the same sequence.
• The Red-Black tree method is used by TreeSet to sort the elements. TreeSet is a great option if you frequently need to perform read/write operations.
The Set interface is offered by the Java.util package. The set interface is made by extending the collection interface. Since it won't allow it, we won't be able to add the same element. Due to the elements' sorted order, it does not maintain the insertion order. Java's Set interface is used to construct the mathematical Set.
Map is used to store an object collection as a single entity, much how Set is used to store an object collection as a single entity. A key-value pair is saved for each item. Because each value is associated with a different key, we can quickly obtain the value using just the key.
To determine if two items are identical, use the equals method. We must override the property if we wish to check the objects depending on it.
For instance, the class Employee has the following three data members: id, name, and salary. However, we need to guarantee that the employee object has an equivalent wage. The equals() method has to be modified after that.
When the objects need to be handled in priority order, a PriorityQueue is used. The PriorityQueue is used when a queue's components need to be treated in priority order even though a queue is often thought to operate according to the First-In-First-Out principle. The base of the PriorityQueue is a priority heap. The priority queue's members are ordered either by natural ordering or using a Comparator that is supplied at queue creation time.
Java's PriorityQueque class complies with the interfaces for Serializable, IterableE>, CollectionE>, and QueueE>.
Set | map |
---|---|
It is not possible for it to always have the same values. The same elements cannot be added to a set more than once. Every class that complies with the Set interface only stores unique values. | There's a chance that several keys will have the same value. The map has repeating values in addition to a unique key. |
The keyset() and entryset() methods make it simple to traverse through the entries in the Set. | It is not possible to repeatedly iterate over various map elements. To iterate the elements, we must convert Map to Set. |
The sequence in which items are inserted is not tracked by the Set interface. Some of its classes, such as LinkedHashSet, do, however, maintain the insertion order. | The Map does not keep track of the order of insertion. Two Map classes that perform the same function are TreeMap and LinkedHashMap. |
The differences between Collection and Collections are listed below.
Collection is an interface, while Collections is a class.
List, Set, and Queue are given the fundamental data structure capabilities via the Collection interface. On the other hand, sorting and synchronising the collection's component parts are under the purview of the Collections class.
While the Collections class contains static methods that can be used to carry out numerous actions on a collection, the Collection interface only exposes data structure methods.
The objects used as keys in a hashtable must implement the hashCode and equals functions in order for objects to be saved and retrieved correctly. It is impossible for null to implement these methods because it is not an object. A better and more sophisticated variant of Hashtable is HashMap. HashMap was developed as a response to HashTable's shortcomings.
The load factor is initially set to 0.75. The load factor is multiplied by the original capacity to determine the default capacity.
BlockingQueue now comes with ConcurrentHashMap, Counting Semaphore, CopyOnWriteArrayList, and additional concurrent Utility classes. The BlockingQueue interface adds blocking if either BlockingQueue is full or empty, allowing flow control in addition to queueing.
Until another thread dequeues one or more elements or clears the queue fully, a thread trying to enqueue an element in a full queue will be blocked. Additionally, until another thread inputs something, a thread cannot remove anything from an empty queue. Null values are not permitted in BlockingQueue. There are Java BlockingQueue implementations that are thread safe. All of the methods in BlockingQueue use internal locks or other concurrency management strategies and are atomic.
The hashCode() method returns a hash code's value (an integer number). The hashCode() method gives the same integer value if two keys (as determined by the equals() function) are identical.
However, it is possible for two hash code numbers to have unique or similar keys. The hashcode() method will provide a different integer result for both objects if the equals() function does not produce an equal result for two objects.
HashSet is an implementation of the Set Interface that stops values from being duplicated. To ensure that our collection does not contain duplicate data, objects in HashSet must override the equals() and hashCode() methods.
An implementation of the Map Interface called HashMap associates a key with a value. There can be no duplicate keys on a map.
HashSet | Hashmap |
---|---|
The Set Interface has been put into use. | It is in charge of putting the Map Interface into action. |
It prohibits the use of duplicate values. | No two keys may have the same value, and the key must be unique. |
Internally, HashSet uses HashMap to add entries. The HashSet's key K is the parameter given to the add(Object) method. The add(Object) method in Java assigns a dummy value to each value that is supplied to it. | Duplicate values are not even taken into account. |
A crucial component of the Java programming language is arrays. A part of Java's collection system is called an array list. Since ArrayList offers a collection of methods for modifying and accessing components, It is used to access array members.
The data framework In contrast to the data structure Array, ArrayList does not have a defined size. When creating an ArrayList object, the size is not required to be specified. Even though we set a maximum capacity, we can still add more components later.
Arrays can include both primitive data types and class objects, depending on how they are defined. On the other hand, primitive data types are not permitted in ArrayList; only objects are. When we call arraylist, the primitive int data type is converted into an Integer object. add(1);.
Additional actions supported by Java ArrayList include remove and indexOf() (). Arrays do not support these functions.
Using the Collections.unmodifiableList() function, we can quickly make an ArrayList read-only. This function creates a read-only, unmodified representation of the ArrayList from an argument that changes.
import java.util.*; public class Logicmojo { public static void main(String[] args) throws Exception { try { // creating object of ArrayList<String> List<String> sample_list = new ArrayList<String>(); sample_list.add(“practice”); sample_list.add(“solve”); sample_list.add(“interview”); // displaying the initial list System.out.println("The initial list is : " + sample_list); // using unmodifiableList() method List<String> read_only_list = Collections .unmodifiableList(sample_list); // displaying the read-only list System.out.println("The ReadOnly ArrayList is : " + read_only_list); // Trying to add an element to the read-only list System.out.println("Trying to modify the ReadOnly ArrayList."); read_only_list.add(“job”); } catch (UnsupportedOperationException e) { System.out.println("The exception thrown is : " + e); } } }
Output:
The initial list is : [practice, solve, interview] The ReadOnly ArrayList is : [practice, solve, interview] Trying to modify th eReadOnly ArrayList. Exception thrown : java.lang.UnsupportedOperationException
Unbounded Queue: The blocked queue's capacity will be set to an integer. MULTIPLE VALUE An unbounded blocking queue will never block as it has the potential to get very big. As you add more pieces, the length of the line increases.
BlockingQueue unbounded_queue = new LinkedBlockingDeque();
Bounded Queue: The bounded queue is the second kind of queue. The capacity of the queue can be given to the constructor when generating a blocking queue from a bounded queue.
BlockingQueue bounded_queue = new LinkedBlockingDeque(10);
Unique implementations of the Set and Map interfaces are provided by EnumSet and EnumMap, respectively. You must always utilise these implementations when working with enums because of how effective they are.
A bit vector with "ones" at the positions that correspond to the ordinal values of the set's enums is all that makes up an enum set. The implementation need only verify whether the matching bit in the vector is a "one," which is a straightforward procedure to establish whether an enum value is in the set. On the other hand, an EnumMap is an array that can be accessed using the ordinal value of the enum as an index. It is not necessary to compute hash codes or deal with EnumMap conflicts.
Iterators for different collections can be either fail-safe or fail-fast depending on how they respond to concurrent changes. In addition to collection alteration from another thread, concurrent collection modification also covers collection change from the same thread using a different iterator or directly changing the collection.
Fail-fast iterators run through the collection's underlying data structure and throw ConcurrentModificationException when they notice a concurrent update (these iterators are returned by HashMap, ArrayList, and other non-thread-safe collections).
Fail-safe iterators duplicate the structure they traverse through and are returned by thread-safe collections like ConcurrentHashMap and CopyOnWriteArrayList. They make sure alterations are not performed simultaneously. High memory utilisation and iteration through potentially outdated data if the collection is altered are some of its drawbacks.
The following are some approaches for keeping collecting thread safe:
• Collections.synchronizedList(list);
• Collections.synchronizedMap(map);
• Collections.synchronizedSet(set);
When a method that the actual collection type does not support is called, the UnsupportedOperationException exception is thrown.
Developer utilises the call(), add(), and delete() methods to create a read-only list using the syntax "Collections.unmodifiableList(list)". UnsupportedOperationException ought to be thrown openly.
Synchronizing an ArrayList can be done using one of the next two techniques:
The synchronizedList() technique for collections
Utilizing the synchronizedList() method of collections All access to the backup list must be made through the returned list in order to perform serial access. When iterating through the returning list, the user must manually synchronise.
CopyOnWriteArrayList usage:
In this example, an ArrayList variant that is thread-safe is created. T represents generic. All mutative actions (such as add, set, remove, etc.) are implemented in this thread-safe version of the ArrayList by making a separate copy of the underlying array. Contrary to how thread safety is done by vectors and other collections, thread safety is achieved by making a second copy of the List.
Even if copyOnWriteArrayList is modified after an iterator is formed, because the iterator is iterating over a unique copy of the ArrayList while a write operation is taking place on another copy of the ArrayList, the iterator does not result in a ConcurrentModificationException.
• Vector is slightly slower than ArrayList since it is synchronised and thread-safe.
• The primary benefit of Vector is that it synchronises every action you make. A programmer's desire is to synchronise an entire series of events. Activities carried out alone are less secure, and synchronisation is slower.
• Vectors have been declared deprecated in Java and are now regarded as obsolete. Additionally, Vector synchronises each process individually, which is practically never done. Since they almost certainly need to explicitly synchronise the arrayList, most Java programmers opt to use ArrayList instead.
We utilise the ArrayList class's addAll() method to combine the contents of both arraylists into a single new arraylist.
//importing the required header files import java.util.ArrayList; import java.util.Collections; public class Join_Lists { public static void main(String[] args) { //creating the first array list ArrayList<String> list_1 = new ArrayList<String>(); list_1.add("Monday"); list_1.add("Tuesday"); list_1.add("Wednesday"); list_1.add("Thursday"); //printing the first array list System.out.println("The elements of the first array list is as follows : " + list_1); //creating the second array list ArrayList<String> list_2 = new ArrayList<String>(); list_2.add("Friday"); list_2.add("Saturday"); list_2.add("Sunday"); //printing the second array list System.out.println("The elements of the second array list is as follows : " + list_2); //creating the third array list ArrayList<String> joined_list = new ArrayList<String>(); joined_list.addAll(list_1);//adding the elements of the first array list joined_list.addAll(list_2);//adding the elements of the second array list System.out.println("The elements of the joined array list is as follows : " + joined_list); } }