Contents
Memory management
JVM takes care of memory management leaving only some configuration decisions to developers.
Stack and Heap
These are the two memory spaces in JVM.
Stack
- Created for each thread, therefore thread safe.
- Stores local variables, references to the objects on the heap, methods.
- Memory is freed when the methods finish executing and the variables are no longer needed, ordered (LIFO).
- Easy, fast access.
StackOverFlowErrorwhen resources are exhausted, the available memory can be configured with the-Xssoption.
Heap
- Created with an application, it’s shared among all threads.
- Stores the objects and their fields.
- Needs complex memory management techniques like Garbage Collectors to free memory space, there is no order or memory allocation pattern.
- Access is slower.
OutOfMemoryErrorwhen resources are exhausted, the available memory can be configured with the-Xmxand-Xmsoptions.
Generations
Heap memory stores objects according to their age.
Young Generation
- Stores new objects.
- Is cleared with
minor garbage collection. - If an object lives long enough it is promoted to Old Generation.
Old Generation
- Stores the objects promoted from Young Generation.
- Is cleared with
major garbage collection.
Metaspace
It is an off-heap memory manager used to allocate memory for class metadata. When a class loader gets collected, all class metadata it accumulated is released.
Garbage collection
Automatic management for clearing the memory from all objects from Young and Old Generations that are no longer needed.
Garbage-First (G1) Garbage Collector is selected by default on most system configurations. This collector is mostly concurrent, it scales well and keeps garbage collection pauses short.
Manual selection of a garbage collector:
- Adjust the size of the heap space first.
- If that doesn’t help, follow the Oracle guidelines for selecting a collector:
serialcollector for application with small data set, run on a single processor, without pause-time requirements;parallelcollector when peak app performance is a priority and there are no pause-time requirements;mostly concurrentcollector when response time is more important than overall throughput and short collection pauses are required;fully concurrentcollector when response time is a high priority.
Collections
The core collection interfaces are shown in the image below:

General facts:
- Note, that a
Mapis not a trueCollection. However, it’s generally discussed among other collections for the sake of simplicity. - Collection interfaces are
generic. Therefore, we should specify the type of object contained in the collection we’re declaring. - The modification operations in each interface are designated optional. Consult documentation of the selected implementation to make sure you won’t get
UnsupportedOperationExceptionby calling a method that isn’t implemented. - The
Collections.synchronized…methods provides synchronization. e.g.Collections.synchronizedSet(...);. - Fail-fast behavior of an iterator cannot be guaranteed in the presence of unsynchronized concurrent modification.
A simple diagram comparing selected aspects of the most used collections:

Below you’ll find short descriptions of the implementations of the collection interfaces.
List
- insertion order
- duplicate values allowed
- we control where in the list each element is inserted and can access elements by their index
- the
List.of()andList.copyOfmethods return unmodifiable lists - javadoc
General-purpose implementations
ArrayList
- optimized for storing objects, fast random access
- permits null elements
- resizable, the
ensureCapacitymethod may reduce the amount of incremental reallocation - fail-fast iterator
- javadoc
LinkedList
- optimized for data manipulation (inserting and deleting elements)
- permits null elements
- when accessed through the Queue interface, acts as a FIFO queue
- fail-fast iterator
- javadoc
Special-purpose implementations
CopyOnWriteArrayList
- a thread-safe variant of
ArrayList - performant if read-only operations vastly outnumber mutative operations and the set size stays small
- we iterate over an immutable snapshot of the content
- the iterator won’t reflect changes to the list since the iterator was created
- all mutative operations are implemented by making a fresh copy
- javadoc
Time complexity
| List | add() | remove() | get() | contains() | next() | Underlying data structure |
|---|---|---|---|---|---|---|
| ArrayList | O(n) (*) | O(n) | O(1) | O(n) | O(1) | Array |
| LinkedList | O(1) (**) | O(1) | O(n) | O(n) | O(1) | Linked List |
| CopyOnWriteArrayList | O(n) | O(n) | O(1) | O(n) | O(1) | Array |
(*) O(1) if a copy is not needed
(**) O(n) if add(index i)
Set
- unique values
- unspecified behaviour if the value of an element is changed in a manner that affects
equals(caution when storing mutable objects) - the
Set.of()andSet.copyOfmethods return unmodifiable sets - javadoc
General-purpose implementations
HashSet
- not ordered
- permits the null element
- don’t set the initial capacity too high if iteration performance is important
- useful for counting, reports
- fail-fast iterator
- javadoc
LinkedHashSet
- insertion order
- permits the null element
- iteration times for this class are unaffected by capacity
- fail-fast iterator
- javadoc
TreeSet
- elements are ordered using their natural ordering, or by a Comparator provided at creation time
- element comparison is done using
compareTo()method and notequalslike in the Set interface - fail-fast iterator
- javadoc
Special-purpose implementations
EnumSet
- all elements must come from a single enum type
- doesn’t permit the null element (
NullPointerException) - very compact and efficient, operations are likely (though not guaranteed) to be much faster than their
HashSetcounterparts - javadoc
CopyOnWriteArraySet
- uses an internal
CopyOnWriteArrayListfor all of its operations. Thus, it shares the same basic properties. - javadoc
Concurrent implementations
ConcurrentSkipListSet
- insertion, removal, and access operations safely execute concurrently by multiple threads
- elements are ordered using their natural ordering, or by a Comparator provided at creation time
- doesn’t permit the null element
- iterating in ascending order is faster that in descending order
- javadoc
Time complexity
| Set | add() | remove() | contains() | next() | size() | Underlying data structure |
|---|---|---|---|---|---|---|
| HashSet | O(1) | O(1) | O(1) | O(h/n) | O(1) | Hash Map |
| LinkedHashSet | O(1) | O(1) | O(1) | O(1) | O(1) | Hash Table + Linked List |
| TreeSet | O(log(n)) | O(log(n)) | O(log(n)) | O(log(n)) | O(1) | Red-black tree |
| EnumSet | O(1) | O(1) | O(1) | O(1) | O(1) | Bit Vector |
| CopyOnWriteArraySet | O(n) | O(n) | O(n) | O(1) | O(1) | CopyOnWriteArrayList |
| ConcurrentSkipListSet | O(log(n)) | O(log(n)) | O(log(n)) | O(1) | O(n) | ConcurrentSkipListMap |
Map
- unique keys
- unspecified behaviour if the key is changed in a manner that affects
equals(caution when using mutable objects as keys) - a map’s contents can be viewed as a set of keys (
keySet), collection of values (values), or set of key-value mappings (entrySet) - the
Map.of(),Map.copyOfandMap.ofEntriesmethods return unmodifiable maps - javadoc
General-purpose implementations
HashMap
- not ordered
- permits null values and null key
- don’t set the initial capacity too high if iteration performance is important
- useful for counting by the key, local cache
- fail-fast iterator
- javadoc
LinkedHashMap
- insertion order
- in access-ordered linked hash maps, merely querying the map with
getis a structural modification and affects iteration order - fail-fast iterator
- javadoc
TreeMap
- elements are ordered using their natural ordering, or by a Comparator provided at creation time
- element comparison is done using
compareTo()method and notequalslike in the Set interface - fail-fast iterator
- javadoc
Special-purpose implementations
EnumMap
- all keys must come from a single enum type
- maps are maintained in the natural order of their keys (the order in which the enum constants are declared)
- doesn’t permit null keys (
NullPointerException), permits null values - very compact and efficient
- weakly consistent iterator
- javadoc
IdentityHashMap
- intentionally violates Map’s general contract, designed for use only in the rare cases wherein reference-equality semantics are required
- a typical use of this class is topology-preserving object graph transformations (e.g. serialization or deep-copying) or maintaining proxy objects (e.g. maintaining a proxy object for each object in the program being debugged)
- fail-fast iterator
- javadoc
WeakHashMap
- an entry will automatically be removed when its key is no longer in ordinary use
- fail-fast iterator
- javadoc
Concurrent implementations
ConcurrentHashMap
- even though all operations are thread-safe, retrieval operations do not entail locking, and there is not any support for locking the entire table in a way that prevents all access
- all arguments to all task methods must be non-null
- javadoc
ConcurrentSkipListMap
- insertion, removal, update and access operations safely execute concurrently by multiple threads
- elements are ordered using their natural ordering, or by a Comparator provided at creation time
- doesn’t permit null keys or values
- iterating keys in ascending order is faster that in descending order
- weakly consistent iterator
- javadoc
Time complexity
| Map | get() | containsKey() | next() | Underlying data structure |
|---|---|---|---|---|
| HashMap | O(1) | O(1) | O(h / n) | Hash Table |
| LinkedHashMap | O(1) | O(1) | O(1) | Hash Table + Linked List |
| TreeMap | O(log(n)) | O(log(n)) | O(log(n)) | Red-black tree |
| EnumMap | O(1) | O(1) | O(1) | Array |
| IdentityHashMap | O(1) | O(1) | O(h / n) | Array |
| WeakHashMap | O(1) | O(1) | O(h / n) | Hash Table |
| ConcurrentHashMap | O(1) | O(1) | O(h / n) | Hash Tables |
| ConcurrentSkipListMap | O(log(n)) | O(log(n)) | O(1) | Skip List |
Queue and Dequeue
- Queue: usually FIFO, whatever the ordering used, the head of the queue is the element that would be removed by a call to remove or poll
- Dequeue: both FIFO or LIFO, all new elements can be inserted, retrieved and removed at both ends
- Queue javadoc, Dequeue javadoc
General-purpose implementations
LinkedList
- see List
PriorityQueue
- heap implementation
- elements are ordered using their natural ordering, or by a Comparator provided at creation time
- iterator doesn’t guarantee order, use
Arrays.sort(pq.toArray())if you need ordered traversal - doesn’t permit null elements
- javadoc
ArrayDeque
- efficient, resizable array implementation of the Deque interface
- has no capacity restrictions, grows as necessary to support usage
- doesn’t permit null elements
- faster than
Stackwhen used as a stack, faster thanLinkedListwhen used as a queue - fail-fast iterator
- javadoc
Concurrent implementations
ConcurrentLinkedQueue, ConcurrentLinkedDequeue, LinkedBlockingQueue, LinkedBlockingDequeue, ArrayBlockingQueue, PriorityBlockingQueue, DelayQueue, SynchronousQueue, LinkedTransferQueue,
Time complexity
| Queue | offer() | peek() | poll() | remove() | size() | Underlying data structure |
|---|---|---|---|---|---|---|
| LinkedList | O(1) | O(1) | O(1) | O(1) | O(1) | Array |
| PriorityQueue | O(log(n)) | O(1) | O(log(n)) | O(n) | O(1) | Priority Heap |
| ArrayDequeue | O(1) | O(1) | O(1) | O(n) | O(1) | Linked List |
| ConcurrentLinkedQueue | O(1) | O(1) | O(1) | O(n) | O(n) | Linked List |
| LinkedBlockingQueue | O(1) | O(1) | O(1) | O(n) | O(1) | Linked List |
| ArrayBlockingQueue | O(1) | O(1) | O(1) | O(n) | O(1) | Array |
| PriorityBlockingQueue | O(log(n)) | O(1) | O(log(n)) | O(n) | O(1) | Priority Heap |
| DelayQueue | O(log(n)) | O(1) | O(log(n)) | O(n) | O(1) | Priority Heap |
| SynchronousQueue | O(1) | O(1) | O(1) | O(n) | O(1) | None! |
Generics
- Enable types to be parameters when defining classes, interfaces and methods:
public class Box<T> {
private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
}
- Eliminate casting:
List list = new ArrayList();
list.add("hello");
String s = (String) list.get(0);
List<String> list = new ArrayList<String>();
list.add("hello");
String s = list.get(0); // no cast
- Provide type checks at compile time making code more stable.
Type Parameter Naming Conventions
- E - Element (used extensively by the Java Collections Framework)
- K - Key
- N - Number
- T - Type
- V - Value
- S,U,V etc. - 2nd, 3rd, 4th types
- ? - wildcard
Type erasure
- replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded,
- insert type casts if necessary to preserve type safety,
- generate bridge methods to preserve polymorphism in extended generic types.
Restrictions
With generics, you can’t:
- instantiate Generic Types with Primitive Types
- create Instances of Type Parameters
- declare Static Fields Whose Types are Type Parameters
- use Casts or instanceof With Parameterized Types
- create Arrays of Parameterized Types
- create, Catch, or Throw Objects of Parameterized Types
- overload a Method Where the Formal Parameter Types of Each Overload Erase to the Same Raw Type
Questions and Exercises: Generics
Parallel processing
Speedups for parallel compared to sequential forms are common but not guaranteed. Parallel operations involving brief functions on small maps may execute more slowly than sequential forms if the underlying work to parallelize the computation is more expensive than the computation itself. Similarly, parallelization may not lead to much actual parallelism if all processors are busy performing unrelated tasks.