Java Collections Interview Questions You Should Know in 2023 - IQCode

Understanding Java Collections

In Java, a collection refers to a framework that provides a structure for storing and manipulating a group of objects. The Collection Framework, introduced in JDK 1.2, groups all of the collection classes and interfaces. Java Collections provide various capabilities and operations such as searching, sorting, insertion, manipulation, and deletion.

Java Collection Interfaces and Classes

The root interfaces of Java collection classes are the Collection interface and the Map interface. The Java Collection framework contains many interfaces, such as Set, List, Queue, Deque, and their respective classes, such as ArrayList, Vector, LinkedList, PriorityQueue, HashSet, LinkedHashSet, and TreeSet.

The Purpose of the Collection Framework

Before the introduction of the Collection Framework, standard techniques for aggregating Java objects (or collections) were Arrays, Vectors, or Hash Tables. There was no common interface for all of these collections, making implementation independent, and there was no connection between them. The Collection Framework provided a standardized approach, simplifying the implementation and usage of collection classes.

Java Collections Interview Questions for Freshers

1. What is the difference between an array and a collection in Java?

Differentiating between Collection and Collections in Java

In Java,

Collection

is a top-level interface that represents a group of objects. It is the root interface of collection classes in Java such as List, Set, and Queue.

On the other hand,

Collections

is a utility class that provides different methods to manipulate and operate on collections. It has various static methods like sort(), binarySearch(), reverse(), and others that help in carrying out operations on collection objects.

So in essence, "Collection" is the interface to which collection classes like "List", "Set", etc. adhere to, while "Collections" is a utility class providing numerous methods to work with these collection objects efficiently.

Explanation of the Hierarchy of Collection Framework in Java

The Collection Framework in Java provides a set of classes and interfaces that work together to store and manipulate groups of data. The hierarchy of the Collection Framework in Java is as follows:

  • java.util.Collection

    : This is the root interface of the Collection Framework. It defines the basic methods and behaviors that are common to all collections, such as adding and removing elements, checking for membership, and determining the size of the collection.

  • java.util.List

    : This is a subinterface of Collection, and it defines an ordered collection of elements. Elements can be added, removed, and accessed using their indices, much like an array.

  • java.util.Set

    : This is another subinterface of Collection, and it defines a collection of unique elements. Duplicate elements are not allowed in a Set, and the elements are not maintained in any particular order.

  • java.util.Map

    : This is a separate interface that does not extend Collection, but it is still part of the Collection Framework. It defines a mapping between keys and values, much like a dictionary. Each key can map to at most one value, and duplicate keys are not allowed.

  • java.util.Queue

    : This is an interface that extends Collection and defines a collection that supports element insertion and removal at both ends. Queues are typically used to implement FIFO (first-in, first-out) behavior.

Understanding the hierarchy of the Collection Framework in Java is important for choosing the appropriate collection class or interface for a particular task. Each class and interface in the hierarchy provides different functionality and behavior, so it is essential to choose the one that best fits the requirements of the task at hand.

Advantages of the Collection Framework

The Collection Framework in Java provides several advantages to developers, including:

  • Provides a standard way to organize and manipulate groups of objects
  • Improves code reuse and consistency
  • Reduces the complexity of code
  • Offers a variety of implementations of useful data structures and algorithms
  • Enables better performance and efficient memory usage
  • Supports easy integration with other Java technologies

In summary, the Collection Framework is a powerful tool that offers a plethora of benefits to programmers.

Explanation of Interfaces Used in Collection Framework

The Collection Framework in Java includes various interfaces that define a set of methods to be implemented by any class that uses them. Here are some of the most commonly used interfaces in the Collection Framework:

1. List: This interface defines an ordered collection of elements. The elements in a List can be of any type and can be accessed using an index.

2. Set: This interface defines a collection of unique elements. Duplicate elements are not allowed in a Set.

3. Map: This interface defines a mapping between keys and values. Each key must be unique and maps to a single value.

4. Queue: This interface defines a collection for holding elements that can be inserted at one end and removed from the other end.

5. Deque: This interface provides a double ended queue allowing insertion and removal of elements from both ends.

These interfaces are the foundation of the Collection Framework and allow Java developers to efficiently manage and manipulate various groups of related objects in their applications.

Arraylist vs LinkedList: Understanding the Difference

When it comes to data structures, ArrayList and LinkedList are two commonly used options in Java.

ArrayList is a dynamic array implementation. It allows for easy access to elements based on their index and is ideal for cases where elements are frequently added or changed.

LinkedList, on the other hand, uses nodes to store elements and maintains references to the next and/or previous nodes. It's best for scenarios where elements are frequently inserted or removed, as this operation simply requires changing the references between nodes rather than reorganizing all the elements in the list.

In summary, ArrayList is ideal when quick access to elements is needed, while LinkedList works best for frequently changing lists.

// Sample code to demonstrate the difference between ArrayList and LinkedList
ArrayList<String> arrayList = new ArrayList<>(); 
LinkedList<String> linkedList = new LinkedList<>();

arrayList.add("apple");
arrayList.add("banana");
arrayList.add("orange");
 
linkedList.add("apple");
linkedList.add("banana");
linkedList.add("orange");

// Output elements in the ArrayList
System.out.println("Elements in ArrayList: ");
for (String fruit : arrayList) {
   System.out.println(fruit);
}
 
// Output elements in the LinkedList
System.out.println("Elements in LinkedList: ");
for (String fruit : linkedList) {
   System.out.println(fruit);
}


Differences between ArrayList and Vector in Java

Introduction:
Both ArrayList and Vector classes are part of the Java Collection framework and implement the List interface. They are used for dynamic array-based operations, allowing the user to add and remove elements from them dynamically. However, there are some differences between the two classes.

1. Synchronization:
Vector is synchronized, which means that it is thread-safe and can be used in multi-threaded environments, but the performance may be slower due to synchronization overhead. On the other hand, ArrayList is not synchronized and is not thread-safe, meaning that it can only be accessed by one thread at a time. However, synchronization can be externally implemented for ArrayList using Collections.synchronizedList() method.

2. Resizing:
Both ArrayList and Vector dynamically resize themselves to accommodate new elements being added to them. However, Vector resizes itself by doubling its size once it reaches its capacity, while ArrayList increases its size by half of itself. Therefore, Vector is generally more suited for scenarios where there are a lot of insertions into the middle of the data structure.

3. Performance:
Due to synchronization overhead, Vector is generally slower than ArrayList in performance. Therefore, for single-threaded environments, ArrayList is generally preferred.

4. Legacy:
Although Vector was introduced in Java 1.0, it is considered a legacy class, while ArrayList was introduced in Java 1.2 and is generally preferred over Vector unless thread safety is required.

Conclusion:
In summary, ArrayList and Vector are similar in functionality, but their differences lie in synchronization, resizing, and performance. ArrayList is generally preferred in single-threaded environments due to its better performance, while Vector is useful for multi-threaded applications or scenarios where insertion and deletion of elements from the middle of the data structure are frequent.

Differences between List and Set in Java

In Java, List and Set are two collection interfaces that have different properties. Here are some differences between them:

1. Duplicate Elements: List allows duplicate elements, whereas Set does not allow duplicates.

2. Ordering: List maintains the order of elements in which they are inserted, whereas Set does not.

3. Retrieval: List elements can be accessed by their index, whereas Set elements cannot be accessed by index.

4. Implementation: List is implemented by classes such as ArrayList, LinkedList, etc., whereas Set is implemented by classes such as HashSet, TreeSet, etc.

5. Iteration: List can be iterated using an iterator or for-each loop, whereas Set can be iterated using an iterator or enhanced for loop.

It is important to choose the right collection interface based on the requirements of your program. If you need ordered and indexed data with possible duplicates, you can use List. If you need an unordered collection with no duplicates, you can use Set.

Differences Between Iterator and ListIterator in Java

In Java, Iterator and ListIterator are interfaces used to traverse over the elements in a collection. However, there are differences between them:

//Iterator Example Iterator iterator = list.iterator();

while(iterator.hasNext()) { String element = iterator.next(); System.out.println(element); }

//ListIterator Example ListIterator listIterator = list.listIterator();

while(listIterator.hasNext()){ String element = listIterator.next(); System.out.println(element); }

while(listIterator.hasPrevious()){ String element = listIterator.previous(); System.out.println(element); }

1. Positioning: The Iterator interface can be used to traverse over all collections (List, Set, Queue) in forward direction only. On the other hand, ListIterator only works for List collections and can traverse in both forward and backward directions. 2. Element modification: Iterator can only remove the current element from the list while iterating through it, while ListIterator can add, modify or remove elements from the list while iterating through it. 3. Index-Based Operations: ListIterator can perform index-based operations like getting the index of next and previous element. But Iterator does not support these operations.

In summary, use the Iterator interface to traverse over all types of collections in a forward direction while ListIterator interface is specifically used for Lists, with added features such as backward traversal, element modification, and index-based operations.

Difference between HashSet and TreeSet in Java

In Java, HashSet and TreeSet are two commonly used implementations of the Set interface. Both are used to store unique elements, but they have some differences between them. The main differences are as follows:

1. Ordering: HashSet does not maintain any order of elements, while TreeSet stores elements in sorted order.

2. Performance: HashSet provides constant-time performance for the basic operations like add, remove, contains, etc. On the other hand, TreeSet provides logarithmic-time performance for these operations.

3. Methods: HashSet provides only basic methods inherited from the Set interface, while TreeSet provides additional methods like first(), last(), headSet(), and tailSet().

When to use TreeSet: You would prefer to use TreeSet when you need to maintain elements in a sorted order. TreeSet can be used for implementing sorting or navigating an ordered set of elements.

When to use HashSet: You would prefer to use HashSet when order of elements doesn't matter, and you need constant-time performance for basic operations.


// Example usage of HashSet and TreeSet in Java

Set<String> hashSet = new HashSet<>();
hashSet.add("apple");
hashSet.add("banana");
hashSet.add("orange");

Set<String> treeSet = new TreeSet<>();
treeSet.add("apple");
treeSet.add("banana");
treeSet.add("orange");

System.out.println("HashSet: " + hashSet);
System.out.println("TreeSet: " + treeSet);

// Output:
// HashSet: [orange, banana, apple]
// TreeSet: [apple, banana, orange]


Can null elements be added to TreeSet or HashSet in Java?

In Java, HashSet and TreeSet allow null elements to be added. However, only one null element can be added to a HashSet as it does not allow duplicate elements. In contrast, TreeSet does not allow duplicate elements, so it can have only one null element. It's always recommended to avoid the use of null elements in data structures as it can lead to unexpected results and null pointer exceptions.

Priority Queue in Java

In Java, a priority queue is a data structure that stores elements in a specific order. The order is determined by their priorities. The element with the highest priority is always at the front of the queue and the one with the lowest priority is at the back.

In other words, it is an abstract data type that allows efficient access to the minimum or maximum element in a collection. Priority queue can be implemented using a heap, which is a binary tree data structure in which each node has a priority value.

Java's PriorityQueue class is an implementation of a priority queue. It provides the basic operations like insertion and removal of elements. Additionally, it also provides the methods to retrieve the highest priority element, get the current size of the queue, and check if it is empty or not.

Here's an example of how to create a priority queue in Java:

java
import java.util.PriorityQueue;

public class PriorityQueueExample {
   public static void main(String[] args) {
      // Creating a priority queue
      PriorityQueue<Integer> numbers = new PriorityQueue<>();

      // Inserting elements into the queue
      numbers.add(4);
      numbers.add(2);
      numbers.add(1);
      numbers.add(3);
      
      // Printing the elements of the queue
      while (!numbers.isEmpty()) {
         System.out.println(numbers.poll());
      }
   }
}

In this example, we have created a priority queue of integers and added four elements to it. We then printed the elements of the priority queue using the poll() method which retrieves and removes the head of the queue.

Best Practices for Using Java Collections

Java collections offer a convenient and efficient way to work with data structures. Here are some best practices to keep in mind when using Java collections:

  1. Choose the appropriate collection type for your data. Some common collection types include ArrayList, LinkedList, HashSet, and TreeMap.
  2. Avoid using raw types and always specify the type parameter. For example, use List<String> instead of just List when declaring a collection.
  3. Use generics to ensure type safety when adding or retrieving items from a collection.
  4. Prefer the enhanced for loop syntax when iterating over a collection, as it is shorter and less error-prone than the traditional for loop syntax.
  5. Be mindful of the performance characteristics of different collection types. For example, ArrayList is faster for random access, while LinkedList is better for frequent insertions and deletions.
  6. Consider using immutable collections when possible to avoid unintended data modification.
  7. When working with multithreaded applications, use thread-safe collections such as ConcurrentHashMap.
  8. Always initialize your collections with an appropriate initial capacity to avoid unnecessary resizing.
  9. Minimize the number of collection modifications to improve performance, especially for large collections.
  10. Clean up unused collections to prevent memory leaks.
// Example of declaring a type-safe ArrayList
List<String> myList = new ArrayList<>();


Difference between Set and Map in Java

In Java, both Set and Map are interfaces used to store data. However, there are some differences between the two:

1. Use of keys: A Set can only contain unique values, whereas a Map stores values in key-value pairs. The keys in a map are always unique, while the values can be duplicated.

2. Order of elements: A Set does not have a specific order, meaning that the order of elements may change from time to time. A Map can preserve the order of elements if it uses a LinkedHashMap implementation.

3. Retrieving elements: Elements in a Set can be retrieved using an iterator. In a Map, elements can be retrieved using either the key or the value.

4. Performance: Depending on the specific implementation used, performance of Sets and Maps can vary. In general, Sets are faster than Maps for operations that involve adding and removing elements, while Maps are faster when it comes to searching for values using keys.

To summarize, Sets are used to store unique values, while Maps are used to store key-value pairs. When choosing between the two, consider the type of data being stored and the specific requirements of your application.

Differences between HashSet and HashMap

Both HashSet and HashMap are data structures in Java that store collections of objects. However, there are significant differences between the two.

HashSet is used to store a set of unique objects. It does not allow duplicate values and uses the hashcode of the objects to determine their position in the set. On the other hand, HashMap is used to store key-value pairs. It allows duplicate values for different keys, and it uses the hashcode of the keys to determine their position in the map.

HashSet is implemented using a hash table. It provides constant-time performance for basic operations like add, remove, contains, and size. HashMap is also based on a hash table, but it uses an internal mechanism to store both keys and values as separate entries. It provides constant-time performance for the basic operations of put, get, remove, and size.

In summary, while HashSet is used for storing a collection of unique objects, HashMap is used for storing key-value pairs. Both use a hash table structure for efficient storage and retrieval operations.H3. Default Load Factor Size in Hashing-Based Collections

In hashing-based collections, the default load factor size refers to the ratio of the number of elements in the collection to the number of buckets in the hash table. The default value of the load factor is typically 0.75. This means that, by default, the collection will increase the number of buckets when the number of elements reaches 75% of the current number of buckets.

It is possible to change the load factor size by passing a different value as a parameter when creating the collection. For example, a load factor of 0.5 will cause the collection to increase the number of buckets when the number of elements reaches 50% of the current number of buckets. However, changing the load factor can impact the performance of the collection, so it should be done with care.

Difference between Array and ArrayList in Java

In Java, an array is a fixed-length data structure that stores a collection of elements of the same data type in contiguous memory locations while an ArrayList is a dynamic data structure that can grow and shrink in size, stores objects, and provides more functionality than arrays.

Arrays can be multidimensional while ArrayLists are only one-dimensional. Arrays use square brackets [] to access elements while ArrayLists use the get() method. Additionally, arrays can store both primitive and object types, while ArrayLists can store only object types.

One advantage of using an ArrayList is that it can be resized dynamically, unlike an array that has a fixed size once created. However, operations like add and remove can take more time in ArrayLists than in arrays because of the underlying implementation of ArrayLists.

In summary, arrays are a basic data structure with fixed sizes, while ArrayLists are a more advanced data structure that provides easier ways to manipulate data dynamically.

How to Create an Unmodifiable ArrayList in Java?

In Java, you can make an ArrayList read-only, or rather, unmodifiable, by using the Collections class and calling the unmodifiableList() method. This method returns an unmodifiable view of the specified list.


import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Example {
    public static void main(String[] args) {
        // Create a new ArrayList
        List<String> list = new ArrayList<>();
        list.add("item1");
        list.add("item2");
        list.add("item3");
        
        // Get an unmodifiable view of the list
        List<String> readOnlyList = Collections.unmodifiableList(list);
        
        // Attempting to modify the list will result in an UnsupportedOperationException
        readOnlyList.add("item4"); // This will throw an UnsupportedOperationException
    }
}

The above code creates a new ArrayList and adds three items to it. It then obtains an unmodifiable view of the list using the Collections.unmodifiableList() method. Finally, it attempts to add a fourth item to the read-only list, which results in an UnsupportedOperationException.

Java Collections Interview Questions for Experienced: Comparable vs Comparator

In Java, both Comparable and Comparator are interfaces used for sorting objects in a collection. The main difference between them is that Comparable is implemented by the class whose objects need to be sorted, while Comparator is implemented by a separate sorting class.

The Comparable interface defines the natural sorting order of objects based on their attributes. The class that implements Comparable must implement the compareTo() method, which compares the current object with another object of the same class and returns a negative, zero, or positive value depending on their relationship.

The Comparator interface, on the other hand, provides a way to sort objects using different criteria. The sorting logic is defined in a separate class that implements the Comparator interface. The sorting class must implement the compare() method, which takes two objects as arguments and returns a negative, zero, or positive value depending on their relationship.

In summary, Comparable is used for natural sorting order, while Comparator is used for custom sorting order. They both are essential interfaces of Java Collections when it comes to sorting and should be used appropriately.

Understanding BlockingQueue in Java

In Java, BlockingQueue is an interface that extends the Queue interface. It represents a queue that supports operations that wait for the queue to become non-empty when retrieving an element, and wait for space to become available in the queue when adding an element. This feature is particularly useful in multithreaded environments where one thread producing elements can be blocked until another thread consuming elements becomes active.

There are several types of BlockingQueue implementations available in Java, including ArrayBlockingQueue, LinkedBlockingQueue, PriorityBlockingQueue, and SynchronousQueue. Each of these implementations has unique capabilities and specifications, so it's essential to choose the appropriate one based on the specific use case.

Fail-Fast and Fail-Safe Iterators in Java

In Java, iterators are used to iterate over collections. There are two types of iterators in Java: fail-fast and fail-safe iterators.

Fail-Fast Iterator: Fail-Fast iterator throws ConcurrentModificationException if the collection is modified while iterating over it. It is implemented in most of the collection classes of Java like ArrayList, HashSet, and HashMap. Fail-Fast iterator works on the original collection and does not create a copy. It is recommended to use fail-fast iterators in multi-threaded environments because they detect and report any concurrent modification to the collection.

Fail-Safe Iterator: Fail-Safe iterator does not throw ConcurrentModificationException if the collection is modified while iterating over it. Instead of operating on the original collection, fail-safe iterators work on the clone of the original collection. It is implemented in the concurrent collection classes like ConcurrentHashMap, CopyOnWriteArrayList, and CopyOnWriteArraySet. Fail-Safe iterator creates a copy of the original collection and iterates over it. It does not modify the original collection and hence it does not throw any exception. It is recommended to use fail-safe iterators in single-threaded environments because they avoid the overhead of creating a clone in each iteration.

In summary, fail-fast iterators are used in multi-threaded environments to detect and report concurrent modifications, while fail-safe iterators are used in single-threaded environments to avoid the overhead of creating a clone in each iteration.

Purpose of RandomAccess Interface and Example of Collection Type Implementing it

The RandomAccess interface is used to indicate that the elements of a collection can be accessed randomly with the same speed. It does not define any methods, but serves as a marker interface. The purpose of this interface is to allow algorithms to optimize their behavior when dealing with different types of collections. A collection that implements the RandomAccess interface can be expected to provide constant time performance for accessing elements by index, which is useful for certain algorithms.

One example of a collection type that implements the RandomAccess interface is the ArrayList class in Java. This is because the ArrayList uses an array to store its elements and provides constant time access to elements by index. Other collection types, such as LinkedList, do not implement the RandomAccess interface because accessing their elements by index has a time complexity of O(n) and thus is not constant time.

Difference between Iterator and Enumeration

The

Iterator

and

Enumeration

interfaces in Java are used to traverse collections such as arrays, lists, and sets. However, there are some differences between them:

  • Functionality: An iterator allows you to remove elements from the collection during traversal, whereas an enumeration doesn't provide any such functionality.
  • Legacy: Enumeration is a legacy interface that has been replaced by Iterator in modern Java versions.
  • Type: Iterator is a generic interface, whereas Enumeration is not generic.
  • Method names: The method names in the two interfaces are different. For example, to get the next element, you use the
    next()

    method with Iterator and

    nextElement()

    method with Enumeration.

It is recommended to use Iterator over Enumeration for traversing collections in Java as Iterator provides more functionality and is a modern interface.

// Example code for Iterator
Iterator<String> iterator = list.iterator();
while(iterator.hasNext()) {
 String element = iterator.next();
 // do something with the current element
}
// Example code for Enumeration
Enumeration<String> enumeration = vector.elements();
while(enumeration.hasMoreElements()) {
 String element = enumeration.nextElement();
 // do something with the current element
}

Explanation:

The Properties class in Java is used to handle a set of default values that can be loaded from a file. These files are usually in the format of key-value pairs and are stored in a properties file. The advantage of using a properties file is that it provides a convenient way to store and retrieve configuration settings for an application without hardcoding them into the source code.

The Properties class provides methods to load and store data in a properties file. It also provides methods to get and set individual properties from the file. This makes it easy to update and modify configuration settings without changing the source code.

Overall, the use of Properties class and properties file provides a flexible and convenient way to manage configuration settings for a Java application.

Differences between HashMap and HashTable

HashMap and HashTable are both used to store key-value pairs. However, there are some differences between the two:

HashMap:
  • Is not synchronized
  • Allows
    null

    values and

    null

    key

  • Is not thread-safe
  • Uses
    iterator()

    method to traverse

HashTable:
  • Is synchronized
  • Does not allow
    null

    values or

    null

    key

  • Is thread-safe
  • Uses
    enumeration()

    method to traverse

Note: It is recommended to use

HashMap

instead of

HashTable

since it provides better performance and allows

null

values and

null

key.

Why does HashMap allow null whereas Hashtable does not allow null?

In Java, HashMap and Hashtable are two widely used classes that implement the Map interface. The primary difference between them is that Hashtable is synchronized whereas HashMap is not.

Another key difference is that Hashtable does not allow null as a key or value, whereas HashMap allows the use of null for both keys and values. This is because Hashtable was created earlier in the history of Java, and the designers of the class made the decision to disallow null values to prevent potential NullPointerExceptions.

On the other hand, HashMap was introduced later and designers chose to allow nulls, as they could be useful in some scenarios. However, it is generally recommended to avoid using nulls in HashMap or any other data structure whenever possible, as they can lead to ambiguous or unexpected behavior.

Synchronizing an ArrayList in Java

In Java, you can synchronize an ArrayList by using the `synchronizedList()` method from the `Collections` class. This method returns a synchronized (thread-safe) list backed by the specified ArrayList.

Here's an example code snippet:


ArrayList<String> list = new ArrayList<String>();
List<String> synchronizedList = Collections.synchronizedList(list);

Now, the `synchronizedList` can be accessed by multiple threads without any concurrency issues. However, keep in mind that synchronizing an entire list can impact performance. It is recommended to use other thread-safe data structures such as `CopyOnWriteArrayList` if possible.

Reasons for Using Synchronized ArrayList When Vectors Are Available in Java

In Java, ArrayLists and Vectors are both used to store collections of objects. However, Vectors are synchronized, meaning that only one thread at a time can access a Vector object. If a second thread attempts to access a Vector that is already in use by another thread, it will be blocked until the first thread has finished using the Vector.

On the other hand, ArrayLists are not synchronized, which means that multiple threads can access an ArrayList at the same time. While this provides greater speed and efficiency, it can also lead to issues if multiple threads attempt to modify the ArrayList simultaneously. This can result in data corruption or inconsistency.

Therefore, if you are working in a multithreaded environment where multiple threads need to access and modify the same collection of objects, it is recommended to use a synchronized ArrayList instead of an unsynchronized ArrayList. This ensures that all modifications to the collection are done in a thread-safe manner, avoiding any issues with data corruption or inconsistency.

Why doesn't the Map interface extend the Collection interface or vice versa?

The Map interface in Java represents a collection of key-value pairs, while the Collection interface represents a group of objects. Given the fundamental difference in their purposes, it would not make sense for one to extend the other. Additionally, both interfaces have different methods and behaviors. It is more appropriate to keep them as separate interfaces to maintain clarity and organization in Java's API.

Differences Between HashMap and TreeMap in Java

In Java, both `HashMap` and `TreeMap` are used to implement `Map` interface that stores key-value pairs. However, they differ in how they maintain and store their entries.

HashMap: - Uses a hashing function to store entries - Provides constant time O(1) performance for basic operations (get and put) - No ordering is maintained, i.e., entries are not sorted - Allows null values for both keys and values - Not thread-safe (must be synchronized externally)

TreeMap: - Uses a red-black tree to store entries - Provides guaranteed logarithmic time O(log n) performance for basic operations (get and put) - Maintains entries in a sorted natural order, i.e., keys are sorted - Does not allow null keys (throws a `NullPointerException` if attempted to insert null key) - Allows null values - Not thread-safe (must be synchronized externally)

In summary, if you need a fast and efficient Map implementation with no ordering, go with `HashMap`. If you need a Map implementation that maintains a sorted order or you need to leverage the various methods of NavigableMap interface (like `floorKey`, `higherKey`, etc.), go with `TreeMap`.

Java Collection Programs

Program 31:


List<Integer> integerList = new ArrayList<>(Arrays.asList(array));

Where "array" is the name of the integer array that needs to be converted to a collection.

This code creates an ArrayList of Integers and initializes it with the elements of the array by using the asList method of the Arrays class. The ArrayList is then assigned to the integerList variable.

Note: The type of ArrayList and the Integer class can be changed to suit the needs of the program.

Displaying Hashtable Contents using Enumeration in Java


import java.util.Hashtable;
import java.util.Enumeration;

public class HashtableContentsDisplay {

    public static void main(String[] args) {

        // Create a Hashtable object
        Hashtable<String, String> hashtable = new Hashtable<String, String>();

        // Add elements to the Hashtable
        hashtable.put("1", "One");
        hashtable.put("2", "Two");
        hashtable.put("3", "Three");
        hashtable.put("4", "Four");
        hashtable.put("5", "Five");

        // Get the Enumeration object
        Enumeration<String> enumeration = hashtable.elements();

        // Iterate through the Hashtable using Enumeration
        while (enumeration.hasMoreElements()) {
            System.out.println(enumeration.nextElement());
        }
    }
}

In the above program, we have created a Hashtable object and added multiple key-value pairs to it. We then obtain the Enumeration object from the contents of the Hashtable and use it to iterate over each element of the Hashtable using a while loop. The output of the program will be the values of all the elements in the Hashtable.

Program to Shuffle Collection Elements in Java

Here's a code snippet that shuffles all the elements present in a collection:


    Collections.shuffle(collection);

The

shuffle()

method provided by the

Collections

class is used to randomly shuffle the elements present in a collection. It takes the collection as its parameter and shuffles its elements randomly.

Here's an example code that demonstrates the usage of the

shuffle()

method:


import java.util.ArrayList;
import java.util.Collections;

public class ShuffleElements {
    public static void main(String[] args) {
        // Create a list of strings
        ArrayList<String> list = new ArrayList<>();
        list.add("Apple");
        list.add("Banana");
        list.add("Mango");
        list.add("Orange");
        list.add("Pineapple");
        
        // Shuffle the elements of the list
        Collections.shuffle(list);
        
        // Print the shuffled elements of the list
        System.out.println("Shuffled Elements:");
        for(String element: list) {
            System.out.println(element);
        }
    }
}

This code creates an

ArrayList

of strings containing some fruit names. It applies the

shuffle()

method to the list, which shuffles the elements randomly. Finally, it prints the shuffled elements of the list using a

for-each

loop.

Java program to clone a TreeSet to another TreeSet


import java.util.TreeSet;

public class TreeSetClone {
  public static void main(String[] args) {
    // create a TreeSet object
    TreeSet<String> treeSet1 = new TreeSet<String>();

    // add elements to TreeSet
    treeSet1.add("apple");
    treeSet1.add("banana");
    treeSet1.add("orange");

    // clone TreeSet to another TreeSet
    TreeSet<String> treeSet2 = (TreeSet<String>)treeSet1.clone();

    // print the elements of both TreeSets
    System.out.println("Elements in First TreeSet: " + treeSet1);
    System.out.println("Elements in Second TreeSet: " + treeSet2);
  }
}

In this program, we first create a TreeSet object called

treeSet1

and add elements to it using the

add()

method. Then, we clone

treeSet1

to another TreeSet called

treeSet2

using the

clone()

method. Finally, we print the elements of both TreeSets using the

System.out.println()

method.

Java program to get the collection view of values in a HashMap


import java.util.*; 

public class HashMapValuesExample {

   public static void main(String[] args) {

      // Creating HashMap and adding key-value pairs to it
      HashMap<String, Integer> map = new HashMap<String, Integer>();
      map.put("One", 1);
      map.put("Two", 2);
      map.put("Three", 3);
      map.put("Four", 4);
      map.put("Five", 5);

      // Getting the Collection View of Values present in the HashMap
      Collection<Integer> values = map.values();
      
      // Iterating over the Collection View to print each value
      Iterator<Integer> iterator = values.iterator();
      while (iterator.hasNext()) {
         System.out.println(iterator.next());
      }
   }
}

This program creates a HashMap and adds key-value pairs to it. It then retrieves the Collection View of values by calling the values() method on the HashMap object. The Collection is then iterated over to print each value present in the HashMap.

Java program to merge two ArrayLists into one ArrayList


import java.util.ArrayList;
import java.util.List;

public class MergeArrayLists {

   public static void main(String[] args) {
      
      List<Integer> listOne = new ArrayList<>();
      listOne.add(1);
      listOne.add(2);
      listOne.add(3);
      
      List<Integer> listTwo = new ArrayList<>();
      listTwo.add(4);
      listTwo.add(5);
      listTwo.add(6);
      
      List<Integer> mergedList = new ArrayList<>(listOne);
      mergedList.addAll(listTwo);
      
      System.out.println("Merged ArrayList: " + mergedList);
  }
}

In the above Java program, we have created two ArrayLists, 'listOne' and 'listTwo'. Then, we have merged these two ArrayLists into a new ArrayList called 'mergedList'. We have used the addAll() method to add all elements of 'listTwo' to 'mergedList' after creating a shallow copy of 'listOne' using the ArrayList constructor. Finally, we have printed the merged ArrayList using the println() method.

This code can be used as a reference to merge any two ArrayLists in Java.

Technical Interview Guides

Here are guides for technical interviews, categorized from introductory to advanced levels.

View All

Best MCQ

As part of their written examination, numerous tech companies necessitate candidates to complete multiple-choice questions (MCQs) assessing their technical aptitude.

View MCQ's
Made with love
This website uses cookies to make IQCode work for you. By using this site, you agree to our cookie policy

Welcome Back!

Sign up to unlock all of IQCode features:
  • Test your skills and track progress
  • Engage in comprehensive interactive courses
  • Commit to daily skill-enhancing challenges
  • Solve practical, real-world issues
  • Share your insights and learnings
Create an account
Sign in
Recover lost password
Or log in with

Create a Free Account

Sign up to unlock all of IQCode features:
  • Test your skills and track progress
  • Engage in comprehensive interactive courses
  • Commit to daily skill-enhancing challenges
  • Solve practical, real-world issues
  • Share your insights and learnings
Create an account
Sign up
Or sign up with
By signing up, you agree to the Terms and Conditions and Privacy Policy. You also agree to receive product-related marketing emails from IQCode, which you can unsubscribe from at any time.