Java

Java Collections Quick Reference

Introduction

JDK provides a powerful, high quality and high performance reusable data structures and algorithms in a so-called Java Collections Framework. This is a quick reference post to get to know about or using Java Collections interfaces and their implementations.

Looking for what collection class to use?

Follow the flowchart and summary table to select the best collection class for your requirement.

Pairs
Values Only
No
Yes
Yes
No
Yes
No
Insertion Order
Key Sorted
Yes
No
No
Yes
No
Yes
Insertion Order
Value Sorted
Yes
No
Yes
Yes
Yes
No
Yes
No
No
Yes
No
Yes
Start
Contains
key/value pair?
Is Order
Important
Will it contain
duplicate values?
Should it be used as cache
or store construction
expensive objects?
Insertion order or
sorted by order?
WeakHashMap
Unique key to be
determined using
equals() instead '==' oper?
HashMap
IdentityHashMap
LinkedHashMap
Should it be
synchronized?
HashTable
TreeMap
Is element order
Important
Should it be
synchronized?
HashSet
Insertion order or
sorted by values?
LinkedHasSet
TreeSet
Should it act like
LIFO stack?
Fast random
access required?
Stack
Vector
ArrayList
Fast sequential access,
addition/deletion
required?
LinkedList
Should it be used as
as a queue or
double-ended queue?
Does it have to be
fast permorning queue?
ArrayDeque
Collection classesDuplicate elements allowedElements are OrderedElements are SortedIs Thread-safe
ArrayListYesYesNoNo
LinkedListYesYesNoNo
VectorYesYesNoYes
HashSetNoNoNoNo
LinkedHashSetNoYesNoNo
TreeSetNoYesYesNo
HashMapNoNoNoNo
LinkedHashMapNoYesNoNo
HashtableNoNoNoYes
TreeMapNoYesYesNo

In Short, The following characteristics of the main collections in Java Collection Frameworks:

  • All lists allow duplicate elements which are ordered by index.
  • All sets and maps do not allow duplicate elements.
  • All list elements are not sorted.
  • sets and maps do not sort its elements, except TreeSet and TreeMap – which sort elements by natural order or by a comparator.
  • Elements within sets and maps are not ordered, except for: ** LinkedHashSet and LinkedHashMap have elements ordered by insertion order.
  • TreeSet and TreeMap have elements ordered by natural order or by a comparator.
  • There are only two collections are thread-safe, Vector and Hastable. The rest are not thread-safe.

Implementation Classes grouped by their Interfaces

An ordered collection (also known as a sequence). The user of this interface has precise control over where in the list each element is inserted. The user can access elements by their integer index (position in the list), and search for elements in the list.

  • Lists allow duplicate elements
  • Lists allow multiple null elements if they allow null elements at all

  • Resizable-array implementation of the List interface. Implements all optional list operations, and permits all elements, including null. In addition to implementing the List interface, this class provides methods to manipulate the size of the array that is used internally to store the list. (This class is roughly equivalent to Vector, except that it is unsynchronized.)
  • Each ArrayList instance has a capacity. The capacity is the size of the array used to store the elements in the list. It is always at least as large as the list size. As elements are added to an ArrayList, its capacity grows automatically. The details of the growth policy are not specified beyond the fact that adding an element has constant amortized time cost.
  • Note that this implementation is not synchronized. If multiple threads access an ArrayList instance concurrently, and at least one of the threads modifies the list structurally, it must be synchronized externally.
  • To prevent accidental unsynchronized access to the list, create the instance of list as below
List list = Collections.synchronizedList(new ArrayList(...));

  • Doubly-linked list implementation of the `List` and `Deque` interfaces. Implements all optional list operations, and permits all elements ( including null ).
  • All of the operations perform as could be expected for a doubly-linked list. Operations that index into the list will traverse the list from the beginning or the end, whichever is closer to the specified index.

  • A thread-safe variant of ArrayList in which all mutative operations (add, set, and so on) are implemented by making a fresh copy of the underlying array.
  • This is ordinarily too costly, but may be more efficient than alternatives when traversal operations vastly outnumber mutations, and is useful when you cannot or don’t want to synchronize traversals, yet need to preclude interference among concurrent threads.
  • The “snapshot” style iterator method uses a reference to the state of the array at the point that the iterator was created. This array never changes during the lifetime of the iterator, so interference is impossible and the iterator is guaranteed not to throw ConcurrentModificationException. The iterator will not reflect additions, removals, or changes to the list since the iterator was created. Element-changing operations on iterators themselves (remove, set, and add) are not supported. These methods throw UnsupportedOperationException.
  • All elements are permitted, including null.

An object that maps keys to values. A map cannot contain duplicate keys; each key can map to at most one value.

  • The order of a map is defined as the order in which the iterators on the map’s collection views return their elements.
  • Map uses hashCode(), == and equals() for entry lookup. The lookup sequence for a given key k is as follows:
    • Use k.hashCode() to determine which bucket the entry is stored, if any
    • If found, for each entry’s key k1 in that bucket, if k == k1 || k.equals(k1), then return k1’s entry
    • Any other outcomes, no corresponding entry

Some insights on hashCode()

  • To be used as a key in a Hashtable, the object shouldn’t violate the hashCode() contract i.e, equal objects must return the same code.
  • hashCode() is inherited by all Java objects and this method returns int value. Value returned from hashCode() method is calculated from the internal memory address of the object. By default hashCode() returns distinct integers for distinct objects.
  • Any key object will be converted to an integer by hashCode() which might cause the returned integer to be big.
  • To reduce the range of integer returned from hashCode(), methods get(), put(), remove() contains the below piece of code
int index = (hash & 0x7FFFFFFF) % tab.length;

Value of index is a reminder of the division hash by the array size

  • 0x7FFFFFFF - is a 32-bit integer in hexadecimal with all but the highest bit set
  • tab.length - Array size
  • hash - number returned by the key’s hashCode() method

  • This class implements a hash table, which maps keys to values. Any non-null object can be used as a key or as a value.

  • To successfully store and retrieve objects from a hashtable, the objects used as keys must implement the hashCode method and the equals method.

  • Any non-null object can be used as a key or as a value.

  • To successfully store and retrieve objects from a hashtable, the objects used as keys must implement the hashCode method and the equals method.

  • Hashtables can be iterated in few ways

    • Fail Fast: Iteration - ConcurrentModificationException will be thrown after Hashtable is modified after its Iterator is created

      Hashtable<String, String> hashTable = new Hashtable<>();
      hashTable.put("key-1", "value-1");
      hashTable.put("key-2", "value-2");
      
      Iterator<String> it = hashTable.keySet().iterator();
      
      hashTable.remove("key-2");
      
      while (it.hasNext()) {
         String key = it.next();
      }
      
      java.util.ConcurrentModificationException
          at java.util.Hashtable$Enumerator.next(Hashtable.java:1378)
    • Not Fail Fast: Enumeration makes Hashtable not fail-fast

      Hashtable<String, String> hashTable = new Hashtable<>();
      hashTable.put("key-1", "value-1");
      hashTable.put("key-2", "value-2");
      
      Enumeration<String> it = hashTable.keys;
      
      hashTable.remove("key-2");
      
      while (enumKey.hasMoreElements()) {
          String key = enumKey.nextElement();
      }
  • Iteration order in a Hashtable is unpredictable and does not match the order in which the entries were added.

  • If a thread-safe implementation is not needed, it is recommended to use HashMap in place of Hashtable.

  • If a thread-safe highly-concurrent implementation is desired, then it is recommended to use ConcurrentHashMap in place of Hashtable


HashMap is Hash table based implementation of the Map interface. HashMap makes no guarantees as to the iteration order of the map, it does not guarantee that the order will remain constant over time and HashMap permits null key and null values.

HashMap class is equivalent to Hashtable, except that it is `unsynchronized and permits nulls. If multiple threads access a hash map concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally. To prevent accidental unsynchronized access to the list, create the instance of list as below

Map map = Collections.synchronizedMap(new HashMap(...));

LinkedHashMap is just like HashMap with an additional feature of maintaining an order of elements inserted into it. HashMap does quick insertion, search and deletion but it does not maintain the order of insertion. This is achieved by LinkedHashMap which ensures elements are inserted in the order they are inserted and can be accessed in their insertion order.


WeakHashMap is a hash table based implementation of the Map interface, with keys that are of a WeakReference type. An entry in a WeakHashMap will automatically be removed when its key is no longer in ordinary use i.e, that there is no single Reference that point to that key. When the garbage collection (GC) process discards a key, its entry is effectively removed from the map, so this class behaves somewhat differently from other Map implementations.

Bit of info on Strong, Soft and WeakReference

  • The strong reference is the most common type of Reference. Any object which has a strong reference pointing to it is not eligible for GC. The variable description has a strong reference to an String object with its assigned value.
String description = "This variable has Strong Reference to value";
  • Soft reference objects, which are cleared at the discretion of the garbage collector in response to memory demand. An object that has a SoftReference pointing to it won't be garbage collected until the JVM absolutely needs memory. We are wrapping `description` strong reference into a soft reference by reference it to null and making it eligible for GC which will be collected only when JVM absolutely needs memory.
String description = "This variable has Strong Reference to value";
SoftReference<String> soft = new SoftReference<String>(description); 
description = null;
  • Weak reference objects, which do not prevent their referents from being made finalizable, finalized, and then reclaimed. Weak references objects are garbage collected eagerly; the GC won't wait until it needs memory. We are wrapping `description` strong reference into a weak reference by reference it to null and making it eligible to be garbage collected in the next GC cycle, as there is no other strong reference pointing to it.
String description = "This variable has Strong Reference to value";
WeakReference<String> soft = new WeakReference<String>(description); 
description = null;

EnumMap is specialized implementation of Map interface for enumeration types, i.e Enum as its keys.

  • EnumMap is ordered collection and they are maintained in the natural order of their keys i.e Order on which enum constant are declared inside enum type.
  • EnumMap is high performance map implementation, much faster than HashMap.

TreeMap class is a red-black tree based implementation. It provides an efficient means of storing key-value pairs in sorted order.

  • TreeMap contains values based on the key. It implements the NavigableMap interface and extends AbstractMap class.
  • TreeMap contains only unique elements. It cannot have a null key but can have multiple null values.
  • TreeMap maintains ascending order.
  • TreeMap is non synchronized.

ConcurrentHashMap is a hash table supporting full concurrency of retrievals and high expected concurrency for updates.

  • HashMap is not a thread-safe implementation, while Hashtable does provide thread-safety by synchronizing operations, but it is not very efficient. Collections.synchronizedMap, does not exhibit great efficiency.
  • ConcurrentMap is introduced for high throughput under high concurrency.
  • ConcurrentHashMap is thread-safe i.e. multiple thread can operate on a single object without any complications.
  • ConcurrentHashMap cannot have null as key or value.

ConcurrentSkipListMap is scalable concurrent version of TreeMap. When ordering of keys is required, we can use ConcurrentSkipListMap.

  • ConcurrentSkipListMap ensures get, put, containsKey and remove operations are multiple thread based and safe for executing concurrently.
  • ConcurrentSkipListMap does not permit the use of null keys or values because some null return values cannot be reliably distinguished from the absence of elements.

A collection that contains no duplicate elements. Sets contain no pair of elements e1 and e2 such that e1.equals(e2), and at most one null element. That being said as Set is a well-defined collection of distinct objects and in other words, the same object cannot occur more than once.

Java Set and List interfaces are quite similar to each other, but has two major differences.

The first difference is that the same element cannot occur more than once in a Set. This is different from a List where each element can occur more than once.

The second difference is that the elements in a Set has no guaranteed internal order. The elements in a List has an internal order, and the elements can be iterated in that order.


  • HashSet is used to create a collection that uses a hash table for storage. It stores the elements by using a mechanism called hashing.
  • HashSet contains unique elements only and can allow atmost one null value.
  • Elements in HashSet are inserted on the basis of their hashcode and not by their insertion order.
  • Upon creating a new empty instance of HashSet, the backing HashMap instance has default initial capacity (16) and load factor (0.75).
  • HashSet class is non synchronized.

  • LinkedHashSet class is a Hashtable and LinkedList implementation of the set interface. It inherits HashSet class and implements Set interface.
  • LinkedHashSet class contains unique elements only like HashSet and can allow atmost one null value.
  • As LinkedHashSet uses a linked list to store its elements, LinkedHashSet’s iterator returns elements in the order in which they were inserted.
  • LinkedHashSet class is non synchronized.

  • TreeSet implements the NavigableSet interface, which in turn extends the SortedSet interface.
  • TreeSet class internally uses a TreeMap to store elements. The elements in a TreeSet are sorted according to their natural ordering or based on a custom Comparator that is supplied at the time of creation of the TreeSet
  • TreeSet class is non synchronized.

  • A thread-safe variant of HashSet which uses a underlying CopyOnWriteArrayList for all of its operations.
  • As normal set data structure, it does not allow duplicates
  • CopyOnWriteArraySet is costly for update operations, bacause each mutation creates a cloned copy of underlying array and add/update element to it.
  • It is thread-safe version of HashSet. Each thread accessing the set sees its own version of snapshot of backing array created while initializing the iterator for this set.
  • Because it gets snapshot of underlying array while creating iterator, it does not throw ConcurrentModificationException.
  • ConcurrentSkipListSet is scalable concurrent NavigableSet implementation based on a ConcurrentSkipListMap.
  • The elements of the set are kept sorted according to their natural ordering, or by a Comparator provided at set creation time, depending on which constructor is used.
  • Insertion, removal, and access operations safely execute concurrently by multiple threads.
  • ConcurrentSkipListSet does not permit the use of null elements, because null arguments and return values cannot be reliably distinguished from the absence of elements.

Queue represents a data structure designed to have elements inserted at the end of the queue, and elements removed from the beginning of the queue.

Besides basic Collection operations, queues provide additional insertion, extraction, and inspection operations. Each of these methods exists in two forms: one throws an exception if the operation fails, the other returns a special value (either null or false, depending on the operation). The latter form of the insert operation is designed specifically for use with capacity-restricted Queue implementations; in most implementations, insert operations cannot fail.

  • The Queue is used to insert elements at the end of the queue and removes from the beginning of the queue. It follows FIFO concept.
  • The Java Queue supports all methods of Collection interface including insertion, deletion etc.
  • LinkedList, ArrayBlockingQueue and PriorityQueue are the most frequently used implementations.
  • BlockingQueues have thread-safe implementations. If any null operation is performed on BlockingQueues, NullPointerException is thrown.
  • The Queues which are available in java.util package are Unbounded Queues and those available in java.util.concurrent package are the Bounded Queues.
  • All Queues except the Deques supports insertion and removal at the tail and head of the queue respectively. The Deques support element insertion and removal at both ends.
  • All Queues which implement BlockingQueue interface are BlockingQueues and rest are Non-Blocking Queues.
  • BlockingQueues blocks until it finishes it’s job or time out, but Non-BlockingQueues do not.
  • Some Queues are Deques and some queues are PriorityQueues.

Queue Operations:

  • add() - This method is used to add elements at the tail of queue. More specifically, at the last of linked-list if it is used, or according to the priority in case of priority queue implementation.
  • peek() - This method is used to view the head of queue without removing it. It returns Null if the queue is empty.
  • element()- This method is similar to peek(). It throws NoSuchElementException when the queue is empty.
  • remove() - This method removes and returns the head of the queue. It throws NoSuchElementException when the queue is empty.
  • poll() - This method removes and returns the head of the queue. It returns null if the queue is empty.
  • size() - This method return the no. of elements in the queue.

BlockingQueue Operations:

  • put() - Inserts the specified element into this queue, waiting if necessary for space to become available.
  • take() - Retrieves and removes the head of this queue, waiting if necessary until an element becomes available.
  • offer() - Inserts the specified element into this queue, waiting up to the specified wait time if necessary for space to become available.

  • PriorityQueue is used when the objects are supposed to be processed based on the priority heap.
  • PriorityQueue follows First-In-First-Out algorithm, but sometimes the elements of the queue are needed to be processed according to the priority.
  • The elements of the priority queue are ordered according to their natural ordering, or by a Comparator provided at queue construction time, depending on which constructor is used.
  • A priority queue does not permit null elements.
  • The head of this queue is the least element with respect to the specified ordering. If multiple elements are tied for least value, the head is one of those elements — ties are broken arbitrarily.
  • The queue retrieval operations poll, remove, peek, and element access the element at the head of the queue.
  • The norm of the priority queue is that the item removed from the list is of the highest priority.

  • LinkedBlockingQueue class implements the BlockingQueue interface.
  • LinkedBlockingQueue stores the elements internally in FIFO (First In, First Out) order. The head of the queue is the element which has been in queue the longest time, and the tail of the queue is the element which has been in the queue the shortest time.
  • LinkedBlockingQueue keeps the elements internally in a linked structure (linked nodes). This linked structure can optionally have an upper bound if desired. If no upper bound is specified, Integer.MAX_VALUE is used as the upper bound.

  • ArrayBlockingQueue class is a bounded blocking queue backed by an array. By bounded it means that the size of the Queue is fixed. Once created, the capacity cannot be changed.
  • Attempts to put an element into a full queue will result in the operation blocking.
  • Attempts to take an element from an empty queue will also be blocked.
  • This queue orders elements FIFO (first-in-first-out). It means that the head of this queue is the oldest element of the elements present in this queue. The tail of this queue is the newest element of the elements of this queue. The newly inserted elements are always inserted at the tail of the queue, and the queue retrieval operations obtain elements at the head of the queue.

  • PriorityBlockingQueue is an unbounded blocking queue that uses the same ordering rules as class PriorityQueue and supplies blocking retrieval operations.
  • PriorityBlockingQueue does not allow to add any type of element. Elements added should either implement Comparable or do not implement Comparable, on the condition that you provide a Comparator as well.
  • PriorityBlockingQueue will always be sorted by using either the Comparator or the Comparable implementations to compare elements.
  • The highest priority element is always ordered first as per the comparison logic implementation.
  • PriorityBlockingQueue get blocks when removing from an empty queue.
  • PriorityBlockingQueue does not permit null elements.

  • DelayQueue is an unbounded blocking queue of delayed elements, in which the consumer wants to take an element from the queue, they can take it only when the delay for that particular element has expired.
  • Element put into the DelayQueue needs to implement the Delayed interface and it’s getDelay() method return a zero or negative value which indicate that the delay has already elapsed.
  • The head of the queue is the element whose delay expired furthest in the past.
  • If there is no element whose delay has expired yet, there is no head element in the queue and poll() will return null.
  • Even though unexpired elements cannot be removed using take() or poll(), they are otherwise treated as normal elements in the queue. size() method returns the count of both expired and unexpired elements.
  • DelayQueue does not permit null elements because their delay cannot be determined.

  • SynchronousQueue is a type of Blocking Queue which implements BlockingQueue.
  • SynchronousQueue is a blocking queue in which each insert operation must wait for a corresponding remove operation by another thread, and vice versa. This means that the queue can only contain a single element internally.
  • SynchronousQueue allows to exchange information between threads in a thread-safe manner. A thread inserting an element into the queue will be blocked until another thread takes that element from the queue.
  • SynchronousQueue only has two operations: take() and put(), and both of them are blocking.
  • peeking at a synchronous queue is not possible because an element is only present when you try to remove it; we cannot insert an element (using any method) unless another thread is trying to remove it; you cannot iterate as there is nothing to iterate.

  • LinkedTransferQueue class is an implementation of TransferQueue. It is a concurrent blocking queue implementation in which producers may wait for receipt of messages by consumers.
  • LinkedTransferQueue is an unbounded queue on linked nodes.
  • The elements in the LinkedTransferQueue are ordered in FIFO order, with the head pointing to the element that has been on the Queue for the longest time and the tail pointing to the element that has been on the queue for the shortest time.
  • LinkedTransferQueue supplies blocking insertion and retrieval operations.
  • LinkedTransferQueue does not allow null objects.
  • LinkedTransferQueue is thread safe.

Dequeue represents a double ended queue, meaning a queue where you can add and remove elements from both ends of the queue. The name Deque is an abbreviation of Double Ended Queue.

  • It can be used as a queue (first-in-first-out/FIFO) or as a stack (last-in-first-out/LIFO)
  • It provides the support of resizable array and helps in restriction-free capacity, so to grow the array according to the usage.
  • LinkedList class is a pretty standard Deque and Queue implementation. It uses a linked list internally to model a queue or a deque.

  • ArrayDeque provides resizable-array and implements the Deque interface. It is also known as Array Double Ended Queue or Array Deck.
  • ArrayDeque have no capacity restrictions so they grow as necessary to support usage. It grows by allowing users to add or remove an element from both the sides of the queue.
  • ArrayDeque are not thread-safe. They do not support concurrent access by multiple thread.
  • ArrayDeque does not allow null objects.
  • ArrayDeque class is likely to be faster than Stack when used as a stack and likely to be faster than LinkedList when used as a queue.

  • LinkedBlockingDeque is an optionally-bounded blocking deque based on linked nodes.
  • LinkedBlockingDeque optional boundedness is served by passing the required size in the constructor and helps in preventing memory wastage. When unspecified, the capacity is by default taken as Integer.MAX_VALUE.
  • Linked nodes are dynamically created upon each insertion unless this would bring the deque above capacity.

Frequently asked questions

What is the difference between an ordered and a sorted collection?

  • An ordered collection means that the elements of the collection have a specific order. The order is independent of the value. A List is an example.
  • A sorted collection means that not only does the collection have order, but the order depends on the value of the element. A SortedSet is an example.
  • A collection without any order can maintain the elements in any order. A Set is an example.

What is fail safe and fail fast Iterator ?

Java Collections supports two types of Iterator, fail safe and fail fast.

The main distinction between a fail-fast and fail-safe Iterator is whether or not the underlying collection can be modified while its begin iterated. If you have used Collection like ArrayList then you know that when you iterate over them, no other thread should modify the collection. If Iterator detects any structural change after iteration has begun e.g adding or removing a new element then it throws ConcurrentModificationException, this is known as fail-fast behavior and these iterators are called fail-fast iterator because they fail as soon as they detect any modification . Though it’s not necessary that iterator will throw this exception when multiple threads modified it simultaneously. it can happen even with the single thread when you try to remove elements by using ArrayList’s remove() method instead of Iterator’s remove method. Most of the Collection classes e.g. Vector, ArrayList, HashMap, HashSet has fail-fast iterators.

The iterators used by concurrent collection classes e.g. ConcurrentHashMap, CopyOnWriteArrayList and CopyOnWriteArraySet uses a view of original collection for doing iteration and that’s why they doesn’t throw ConcurrentModificationException even when original collection was modified after iteration has begun. This means you could iterate and work with stale value, but this is the cost you need to pay for fail-safe iterator.


What is load factor?

The load factor is a measure of how full the collection(hash table) is allowed to get before its capacity is automatically increased. When the number of entries in the hash table exceeds the product of the load factor and the current capacity, the hash table is rehashed (that is, internal data structures are rebuilt) so that the hash table has approximately twice the number of buckets.

As a general rule, the default load factor (.75) offers a good tradeoff between time and space costs. Higher values decrease the space overhead but increase the lookup cost (reflected in most of the operations of the HashMap class, including get and put). The expected number of entries in the map and its load factor should be taken into account when setting its initial capacity, so as to minimize the number of rehash operations. If the initial capacity is greater than the maximum number of entries divided by the load factor, no rehash operations will ever occur.


What is Natural Ordering?

Natural ordering is the default ordering of objects of a specific type when they are sorted in an array or a collection. The Java language provides the Comparable interface that allows us define the natural ordering of a class. This interface is declared as follows:

public interface Comparable<T> {
    public int compareTo(T object);
}

As observed, this interface is parameterized (generics) and it has a single method compareTo() that allows two objects of a same type to be compared with each other. The important point here is the value returned by this method: an integer number indicates the comparison result of two objects.

Rules to remember: compare value = 0: two objects are equal. compare value > 0: the first object (the current object) is greater than the second one. compare value < 0: the first object is less than the second one.

Collections are sorted by natural ordering of its elements:

  • The natural ordering of String objects is alphabetic order.
  • The natural ordering of Integer objects is alphanumeric order.
  • The natural ordering of Date objects is chronological order.

How to Override equals() and hashCode()

It is recommended practice to override both equals and hashCode methods when comparing two Java objects.

Simple approach

Below is simple approacg to override equals & hashcode methods in a pojo class

public class Employee {

    private int id;
    private String name;
    private String address;

	//getters and setters, constructor

    @Override
    public boolean equals(Object o) {

        if (o == this) return true;
        if (!(o instanceof Employee)) {
            return false;
        }

        Employee employee = (Employee) o;

        return employee.name.equals(name) &&
                employee.id == id &&
                employee.address.equals(address);
    }

    @Override
    public int hashCode() {
        // 15 * 28 are some random integers to derive the hashcode value
        int hashCode = 15;
        hashCode = 28 * hashCode + name.hashCode();
        hashCode = 28 * hashCode + id;
        hashCode = 28 * hashCode + address.hashCode();
        return hashCode;
    }
}

Using Objects.hash()

Objects class includes utility method equals() && hash() to generate the equals and hash code values.

public class Employee {

    private int id;
    private String name;
    private String address;

	//getters and setters, constructor

    @Override
    public boolean equals(Object o) {

        if (o == this) return true;
        if (!(o instanceof Employee)) {
            return false;
        }
        Employee employee = (Employee) o;
        return id == employee.id &&
                Objects.equals(name, employee.name) &&
                Objects.equals(address, employee.address);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name, address);
    }
}

Using Apache Commons Lang

Apache Commons Lang library has got utility classes EqualsBuilder and HashCodeBuilder to perform equal operation & hashCode generations

@Override
public boolean equals(Object o) {

    if (o == this) return true;
    if (!(o instanceof Employee)) {
        return false;
    }

    Employee employee = (Employee) o;

    return new EqualsBuilder()
            .append(id, employee.id)
            .append(name, employee.name)
            .append(address, employee.address)
            .isEquals();
}

@Override
public int hashCode() {
    return new HashCodeBuilder(15, 28)
            .append(id)
            .append(name)
            .append(address)
            .toHashCode();
}

Using Lombok

Lombok provides an efficient implementation by automatically generating the overridden methods.
@EqualsAndHashCode
public class Employee {
    private int id;
    private String name;
    private String address;

	//getters and setters, constructor
}

How Set interface implemented classes like HashSet, LinkedHashSet, TreeSet etc. achieve this uniqueness?

To add an element to Set we need to use add() method. add() method returns false when we try to add a duplicate element which indicates element is not added to set.


Difference between ArrayList and Vector?

java.util.Vector came along with the first version of java development kit (JDK). java.util.ArrayList was introduced in java version1.2, as part of java collections framework.

All the methods of Vector is synchronized. But, the methods of ArrayList is not synchronized. All the new implementations of java collection framework is not synchronized.

Vector and ArrayList both uses Array internally as data structure. They are dynamically resizable. Difference is in the way they are internally resized. By default, Vector doubles the size of its array when its size is increased. But, ArrayList increases by half of its size when its size is increased.

Therefore as per Java API the only main difference is, Vector’s methods are synchronized and ArrayList’s methods are not synchronized.


Difference between HashMap and HashTable?

Similarities in both the classes:

  • Fail-fast iteration
  • Unpredictable iteration order

Differences between both the classes:

  • HashMap doesn’t provide any Enumeration, while Hashtable provides not fail-fast Enumeration.
  • Hashtable doesn’t allow null keys and null values, while HashMap do allow one null key and any number of null values
  • Hashtable’s methods are synchronized while HashMaps’s methods are not synchronized.

Difference between HashMap and EnumMap?

  • HashMap extends AbstractMap and implement Map interface, EnumMap extends AbstractMap class which implements Map interface.
  • HashMap internally uses HashTable, on the other hand EnumMap internally uses arrays and thus representation is extremely compact and efficient.

Below is the brief difference between HashMap & EnumMap

HashMapEnumMap
HashMap is general purpose map implementation, internally uses HashTable. HashMap can use any object as key.EnumMap is optimized for Enum type keys to store in map. EnumMap internally using as arrays, this representation is extremely compact and efficient, provide constant time performance for common methods like get, and put.
HashMap performance is not better as EnumMap.Due to specialized optimization done in EnumMap, its performance is better than HashMap.
All type of object can use as keys in HashMap.Only Enum type can use as keys in EnumMap.
HashMap using hashCode() to store the keys and values so there is probability of collision.Since EnumMap internally maintain an array and they are stored in their natural order using ordinal(), so there is no probability of collision.
HashMap is not ordered, HashMap order can change over the time.EnumMap stores keys in the natural order of their keys, the order in which the enum constants are declared.

ordinal() - The ordinal() method returns the order of an enum instance. It represents the sequence in the enum declaration, where the initial constant is assigned an ordinal of ‘0’. It is very much like array indexes.It is designed for use by sophisticated enum-based data structures, such as EnumSet and EnumMap.

public enum STATUS 
{
   ACTIVE, INACTIVE, DELETED
}

STATUS.ACTIVE.ordinal();     //0
 
STATUS.DELETED.ordinal();    //2

Difference between Enumeration and Iterator?

The functionality of Enumeration and the Iterator are same. Using Enumeration you can only traverse and fetch the objects, where as using Iterator we can also add and remove the objects. Iterator can be useful if you want to manipulate the list and Enumeration is for read-only access.

IteratorEnumeration
Iterator is applicable for all the collection classes.Enumeration applies only to legacy classes.
Iterator has the remove() method.Enumeration does not have the remove() method.
Iterator can do modifications. Calling remove() during collection traversal will remove the element from the Collection.Enumeration acts as a read only interface, one can not do any modifications to Collection while traversing the elements.
Iterator is not a legacy interface. Iterator can be used for the traversal of HashMap, LinkedList, ArrayList, HashSet, TreeMap, TreeSet.Enumeration is a legacy interface which is used for traversing Vector, Hashtable.

References

Contents

Get The Best Of All Hands Delivered To Your Inbox

Subscribe to our newsletter and stay updated.