Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

Sunday, June 7, 2015

Java 8 Features

Lambda expressions allow to pass in a block of code, a function without a name. The -> separates the parameter from the body of the lambda expression. The parameter of lambda expression does not have a type as the type is inferred from the context of the variable. The lambda method parameters are statically typed. Some different ways of writing lambda expressions areas below:

// 1) empty pair of parentheses, (), can be used to signify that there are no arguments.

Runnable noArguments = () -> System.out.println("Hello World");
// 2) when there is only one argument to the lambda expression we can leave out the parentheses around the arguments.

ActionListener oneArgument = event -> System.out.println("button clicked");
// 3) full block of code, bookended by curly braces ({})

Runnable multiStatement = () -> {
   System.out.print("Hello");
   System.out.println(" World");
};
// 4) This creates a function that adds together two numbers, were the variable called add 
//    isn’t the result of adding up two numbers; it is code that adds together two numbers.

BinaryOperator<Long> add = (x, y) -> x + y;
// 5) providing explicit type to arguments requires to surround the arguments to the lambda expression with parentheses. 
//    The parentheses are also necessary if you’ve got multiple arguments.

BinaryOperator<Long> addExplicit = (Long x, Long y) -> x + y;

The target type of a lambda expression is the type of the context in which the lambda expression appears—for example, a local variable that it’s assigned to or a method parameter that it gets passed into.

Lambda expressions only use final variables since they capture values, not variables. Although we are not required to declare the variable(s) as final, we cannot use them as nonfinal variable(s) if they are to be used in lambda expressions. If you assign to the variable multiple times and then try to use it in a lambda expression, you’ll get a compile error.

Lambda expressions are statically typed, and these types of lambda expressions are called functional interfaces. A functional interface is an  interface with a single abstract method that is used as the type of a lambda expression.

Table 2-1. Important functional interfaces in Java
Interface name Arguments Returns Example
Predicate<T> T boolean Has this album been released yet?
Consumer<T> T void Printing out a value
Function<T, R> T R Get the name from an Artist object
Supplier<T> None T A factory method
UnaryOperator<T> T T Logical not (!)
BinaryOperator<T> (T, T) T Multiplying two numbers (*)

Java 8 allows you to leave out the types for whole parameters of lambda expressions. Java compiler looks for information close to the lambda expression and uses this information to figure out what the correct type should be. It’s still type checked and provides all the safety that you’re used to, but you don’t have to state the types explicitly. This is what we mean by type inference.

A Predicate is a functional interface that checks whether something is true or false. It is also a lambda expression that returns a value, unlike the previous ActionListener examples.
Predicate<Integer> atLeast5 = x -> x > 5;

Here the return value of the lambda expression is the value its body evaluates to.

BinaryOperator is a functional interface that takes two arguments and returns a value, all of which are of same type. It takes only a generic argument. If no generic argument is specified the code doesn't compile.
BinaryOperator<Long> addLongs = (x, y) -> x + y;

Some of the Key Points on Lambda Expressions:
  • A lambda expression is a method without a name that is used to pass around behavior as if it were data.
  • Lambda expressions look like this: BinaryOperator<Integer> add = (x, y) ? x + y.
  • A functional interface is an interface with a single abstract method that is used as the type of a lambda expression.

Streams

In for loop for collections, the iteration proceeds by creating a new Iterator object and then explicitly calling the hasNext and next methods on the Iterator. Hence its too hard to abstract away the different behavioral operations and is inherently serial in nature.

Streams allow to write collections-processing code at a higher level of abstraction. A Stream is a tool for building up complex operations on collections using a functional approach. The Stream interface contains a series of functions each of which corresponds to a common operation that we might perform on a Collection. The call to stream() returns a Stream which is an equivalent interface with the Iterator in the internal iteration of collection.
long count = allArtists.stream().filter(artist -> artist.isFrom("London")).count();

The operations using Streams API does not change the contents of collection but declared the contents of the Stream. The Stream object returned isn’t a new collection—it’s a recipe for creating a new collection. The filter method of the Stream above keeps only those objects that pass a test by returning either true or false. The call to filter builds up a Stream recipe, but there’s nothing to force this recipe to be used. Methods such as filter that build up the Stream recipe but don’t force a new value to be generated at the end are referred to as lazy. Methods such as count that generate a final value out of the Stream sequence are called eager. If the operation gives back a Stream, it’s lazy; if it gives back another value or void, then it’s eager. The values in the Stream that are operated on are derived from the initial values and the recipe produced by the sequence of Stream calls.

The collect(toList()) is an eager operation that generates a list from the values in a Stream.
List<String> collected = Stream.of("a", "b", "c").collect(Collectors.toList());

The map operation allows to apply a function (say converting a value of one type into another) to a stream of values, producing another stream of the new values. It is an instance of Function.
List<String> collected = Stream.of("a", "b", "hello").map(string -> string.toUpperCase()).collect(toList());

The filter method on the stream allows to check each element of the collection. The Stream after the filter has the elements of the Stream
beforehand, which evaluated to true. It is an instance of Predicate interface.

The flatMap method allows to replace a value with a Stream and concatenates all the streams together. It is a variant of map operation which produces a new Stream object as the replacement. It is associated with functional interface but its return type is restricted to streams and not any value.
// Takes Stream of lists of numbers and returns all the numbers from in the sequences.

List<Integer> together = Stream.of(asList(1, 2), asList(3, 4)).flatMap(numbers -> numbers.stream()).collect(toList());

The max and min methods of stream API finds the maximum or minimum element in the streams. The Comparator is passed to determine the ordering of the elements. The comparing method in java 8 allows to build a Comparator using keys. The getter function for the value allows to get the same element out of both elements being compared. When the max method is called on an empty Stream it returns an Optional value, which represents a value that may exist, or may not.
Track shortestTrack = tracks.stream().min(Comparator.comparing(track -> track.getLength())).get();

The reduce operation is used to generate a single result from a collection of values. It takes the initial count and the lambda expression. The count always starts with 0 which is the count of an empty Stream. The type of the reducer is a BinaryOperator.
int count = Stream.of(1, 2, 3).reduce(0, (acc, element) -> acc + element);

Higher-order functions: A higher-order function is a function that either takes another function as an argument or returns a function as its result. If a functional interface is used as a parameter or return type, then we have a higher-order function. Nearly all the functions that we’ve encountered on the Stream interface are higher-order functions. Comparator is also a functional interface as it has only a single abstract method.

Streams describes the operations on data by saying what transformation is made rather than how the transformation occurs. They help to get towards an idea of side effect–free function. Functions with no side effects don’t change the state of anything else in the program or the outside world. Lambda expressions allow to capture values rather than capturing variables (as variables are final), hence promoting to write code free from side effects. The only exception to this is the forEach method, which is a terminal operation.

Java 8 introduces default methods and static methods on interfaces enabling to have methods with bodies containing code.

Boxed types which wrap up the primitive types are objects and have a memory overhead. An primitive int takes 4 bytes of memory, an boxed type Integer takes 16 bytes. Further an Integer[] take up nearly six times more memory than an int[] of the same size. There is also a computational overhead when converting from a primitive type to a boxed type (boxing) and vice versa (unboxing). The streams library hence differentiates between the primitive and boxed versions of some library functions e.g. mapToLong higher-order function and ToLongFunction.
        If the return type is a primitive, the interface is prefixed with To and the primitive type, as in ToLongFunction. If the argument type is a primitive type, the name prefix is just the type name, as in LongFunction. If the higher-order function uses a primitive type, it is suffixed with To and the primitive type, as in mapToLong. These methods such as mapToLong return specialized streams such as IntStream, DoubleStream and LongStream instead of Stream. The min, max, average, sum along with summaryStatistics methods are all available on all three primitive specialized Stream variants.

While overloading the methods, java infers the type of lambda to be the most specific functional interface when calling these methods.
  • If there is a single possible target type, the lambda expression infers the type from the corresponding argument on the functional interface.
  • If there are several possible target types, the most specific type is inferred.
  • If there are several possible target types and there is no most specific type, you must manually provide a type.

@FunctionalInterface is an annotation that should be applied to any interface that is intended to be used as a functional interface. The new interfaces provide Stream interoperability and are really there to bundle up blocks of code as data. Interfaces such as java.lang.Comparable and java.io.Closeable have only a single method (which depends on the object's internal state) but aren’t normally meant to be implemented by lambda expressions. The @FunctionalInterface annotation can be applied to such interfaces enabling them to be used with lambda expressions.

Default Methods allow to let the implementing classes of the interface use their implementation e.g. the stream method of collection or forEach method on Iterable. Unlike classes, interfaces don’t have instance fields, so default methods can modify their child classes only by calling methods on them. This helps to avoid making assumptions about the implementation of their children. The default method is a virtual method opposite of a static method. The class or concrete method override always takes precedence over the default method. If a child class extends a parent class which in turn implemented an interface with a default method. Then the child class also implemented another interface with the default method of the same signature. But the default method from the parent class takes precedence over the default method from the interface.

When a class implements multiple interface with the same default method it results in the compile error. With the new enhanced super syntax i.e. using the InterfaceName.super variant it’s possible to specify a method from an inherited interface.

Below are the rules for multiple inheritance for default methods.
  1. Any class wins over any interface. So if there’s a method with a body, or an abstract declaration, in the superclass chain, we can ignore the interfaces completely.
  2. Subtype wins over supertype. If we have a situation in which two interfaces are competing to provide a default method and one interface extends the other, the subclass wins.
  3. No rule 3. If the previous two rules don’t give us the answer, the subclass must either implement the method or declare it abstract.
The default methods avoids multiple inheritance of state but rather allows inheritance of blocks of code. Java 8 enables static methods on an interface e.g the of() method of the Stream interface.

Optional is a new core library data type that is designed to provide a better alternative to null. null is often used to represent the absence of a value, and this is the use case that Optional is replacing. The problem with using null in order to represent absence is the dreaded NullPointerException. Optional encourages the coder to make appropriate checks as to whether a variable is null in order to avoid bugs. Second, it documents values that are expected to be absent in a class’s API. The factory method is used to create an Optional instance from a value. The empty factory method of Optional is used to represent Optional as an absent value. Also a a nullable value can be converted into an Optional using the ofNullable method.

A common idiom you may have noticed is the creation of a lambda expression that calls a method on its parameter.
artist -> artist.getName()
Such common idiom can be written using method reference as below:
Artist::getName
The standard form of method reference is Classname::methodName. There are no method brackets, since we are not actually calling the method but providing the equivalent of a lambda expression that can be called in order to call the method. Constructors can also be called using the same abbreviated syntax as below:
(name, nationality) -> new Artist(name, nationality) // original
Artist::new // creating an Artist object
String[]::new // creating String array

Method references automatically support multiple parameters, as long as you have the right functional interface.

Element Ordering
The encounter order is defined depends on both the source of the data and the operations performed on the Stream. When you create a Stream from a collection with a defined order e.g. List, the Stream has a defined encounter order. When we try to map values and there’s a defined encounter order, then that encounter order will be preserved. When there’s no encounter order on the input Stream, there’s no encounter order on the output Stream. Most operations, such as filter, map, and reduce, can operate very efficiently on ordered streams. Although ordering can be removed by using stream's unordered method. The forEachOrdered method provides an ordering guarantee compared to forEach method especially while using parallel streams.

The collector is a general-purpose construct for producing complex values from streams. These can be used with any Stream by passing them into the collect method. The collectors can be statically imported from the java.util.stream.Collectors class.
The toList collector produces java.util.List instances, while the toSet and toCollection collector produces instances of Set and Collection.
List<Integer> numbers = asList(1, 2, 3, 4);
List<Integer> stillOrdered = numbers.stream().map(x -> x + 1).collect(toList());
By calling toList or toSet we don’t get to specify the concrete implementation of the List or Set and the implementation is picked by stream library.

The collector e.g. toCollection can take a function to build a specified type of collection as its argument as below:
stream.collect(toCollection(TreeSet::new));

Also single value can be collected using collector such as maxBy and minBy collectors.
public Optional<Artist> biggestGroup(Stream<Artist> artists) {
   // defines a lambda expression that can map an artist to the number of members
   Function<Artist,Long> getCount = artist -> artist.getMembers().count();
   return artists.collect(maxBy(comparing(getCount)));
}

The averagingInt method takes a lambda expression in order to convert each element in the Stream into an int before averaging the values as below.
public double averageNumberOfTracks(List<Album> albums) {
    return albums.stream().collect(averagingInt(album -> album.getTrackList().size()));
}

A collector partitioningBy takes a stream and partitions its contents into two groups. It uses a Predicate to determine whether an element should be part of the true group or the false group and returns a Map from Boolean to a List of values.
public Map<Boolean, List<Artist>> bandsAndSolo(Stream<Artist> artists) {
 // The method reference Artist::isSolo can be also written as artist -> artist.isSolo()
 return artists.collect(partitioningBy(Artist::isSolo));
}

The groupingBy collector takes a classifier function in order to partition the data similar to the partitioningBy collector which took a Predicate to split it up into true and false values. Below is an example which groups a Stream of albums by the name of their main musician. The groupingBy form below divides elements into buckets. Each bucket gets associated with the key provided by the classifier function, e.g. here its getMainMusician. The groupingBy operation then uses the downstream collector to collect each bucket and makes a map of the results.
public Map<Artist, Long> numberOfAlbums(Stream<Album> albums) {
    return albums.collect(groupingBy(album -> album.getMainMusician(),
    counting()));
}

The mapping collector allows to perform a map-like operation over the collector’s container. The mapping collector needs the collection to store the results, which can be done using the toList collector.
public Map<Artist, List<String>> nameOfAlbums(Stream<Album> albums) {
    return albums.collect(groupingBy(Album::getMainMusician,
    mapping(Album::getName, toList())));
}

In both the above cases, the second collector is used in order to collect a subpart of the final result, hence also called downstream collectors.

Comma separated string from the formatted list can be generated using Collectors.joining which collects the Stream to string as below:
String result =
    artists.stream()
              .map(Artist::getName)
              .collect(Collectors.joining(", ", "[", "]"));

Data Parallelism

Amdahl’s Law is a simple rule that predicts the theoretical maximum speedup of a program on a machine with multiple cores. If we take a program that is entirely serial and parallelize only half of it, then the maximum speedup possible, regardless of how many cores we throw at the problem, is 2×. Given a large number of cores—and we’re already into that territory—the execution time of a problem is going to be dominated by the serial part of that problem

When we have a Stream object, we can call its parallel method in order to make it parallel. If we’re creating a Stream from a Collection, we can call the parallelStream method in order to create a parallel stream from the get-go. Below is the example which calculates the total length of a sequence of albums in parallel.
public int parallelArraySum() {
    return albums.parallelStream()
                 .flatMap(Album::getTracks)
                 .mapToInt(Track::getLength)
                 .sum();
}

The kinds of problems that parallel stream libraries excel at are those that involve simple operations processing a lot of data, such as Simulations. Below is the example of parallel Monte Carlo simulation. Here we first use the IntStream range function to create a stream of size N, then call the parallel method in order to use the parallel version of the streams framework. The twoDiceThrows function simulates throwing two dice and returns the sum of their results, which is used on the data stream using the mapToObj method. All the simulation results are combined using the groupingBy collector. Then the numbers are mapped to 1/N and added using the summingDouble function.
public Map<integer double=""> parallelDiceRolls() {
    double fraction = 1.0 / N;
    return IntStream.range(0, N)
            .parallel()
            .mapToObj(twoDiceThrows())
            .collect(groupingBy(side -> side,
                                summingDouble(n -> fraction)));
}

When calling reduce the initial element could be any value, but for same operation to work correctly in parallel, it needs to be the identity value of the combining function. The identity value leaves all other elements the same when reduced with them. For example, if we’re summing elements with our reduce operation, the combining function is (acc, element) -> acc + element. The initial element must be 0, because any number x added to 0 returns x. Another caveat specific to reduce is that the combining function must be associative. This means that the order in which the combining function is applied doesn’t matter as long the values of the sequence aren’t changed.

The streams framework deals with any necessary synchronization itself, so there’s no need to lock the data structures. If we tried to hold locks on any data structure that the streams library is using, such as the source collection of an operation then it would likely cause issues. Stream also has a sequential method other than the parallel method. When a stream pipeline is evaluated, there is no mixed mode, i.e. the orientation is either parallel or sequential. If a pipeline has calls to both parallel and sequential, the last call wins. Under the hood, parallel streams back onto the fork/join framework. The fork stage recursively splits up a problem, were each chunk is operated upon in parallel and then the results are merged back together in the the join stage.

The common data sources from the core library can be split up into three main groups by performance characteristics:

The good: An ArrayList, an array, or the IntStream.range constructor. These data sources all support random access, which means they can be split up arbitrarily with ease.
The okay: The HashSet and TreeSet. These cannot be decomposed easily with perfect amounts of balance, but most of the time it’s possible to do so.
The bad: Some data structures don’t split well; for example, they may take O(N) time to decompose. Examples here include a LinkedList, which is computationally hard to split in half. Also, Streams.iterate and BufferedReader.lines have unknown length at the beginning, so it’s pretty hard to estimate when to split these sources.

Ideally, once the streams framework has decomposed the problem into smaller chunks, we’ll be able to operate on each chunk in its own thread, with no further communication or contention between threads.

Java 8 includes a couple of other parallel array operations that utilize lambda expressions outside of the streams framework These operations are all located on the utility class Arrays, which also contains a bunch of other useful array-related functionality from previous Java versions

Name Operation
parallelPrefix Calculates running totals of the values of an array given an arbitrary function
parallelSetAll Updates the values in an array using a lambda expression
parallelSort Sorts elements in parallel

The parallelSetAll method is used to easily initialize an array in parallel instead of using a for loop. An array is provided to operate on and a lambda expression, which calculates the value given the index. The array passed into the operation is altered, rather than creating a new copy.
public static double[] parallelInitialize(int size) {
      double[] values = new double[size];
      Arrays.parallelSetAll(values, i -> i);
      return values;
}

The parallelPrefix operation is useful for performing accumulation-type calculations over time series of data. It mutates an array, replacing each element with the sum (or any BinaryOperator) of that element and its predecessors. The below example takes a rolling window over a time series and produces an average for each instance of that window.
public static double[] simpleMovingAverage(double[] values, int n) {
      double[] sums = Arrays.copyOf(values, values.length);
      Arrays.parallelPrefix(sums, Double::sum);
      int start = n - 1;
      return IntStream.range(start, sums.length)
                  .mapToDouble(i -> {
                        double prefix = i == start ? 0 : sums[i - n];
                        return (sums[i] - prefix) / n;
                  })
            .toArray();
}


Sunday, April 26, 2015

Core Java Interview Questions

What is the difference between HashMap and Hashtable ?
  • HashTable is thread safe and synchronized, while, HashMap is not synchronized and not thread safe. It is better off externally synchronizing a HashMap using Collections.synchronizedMap(hashMap) or using a ConcurrentMap implementation.
  • Hashmap allows one null key and any number of null values, while Hashtable do not allow null keys and null values in the HashTable object.
  • Hashmap object values are iterated by using iterator .HashTable is the only class other than vector which uses enumerator to iterate the values of HashTable object.
  • The iterator in Hashmap is fail-fast iterator while the enumerator for Hashtable is not.
  • Hashmap is much faster and uses less memory than Hashtable as former is unsynchronized .
  • Hashtable is a subclass of Dictionary class which is now obsolete in Jdk 1.7 ,so ,it is not used anymore. HashMap on other hand is the subclass of the AbstractMap class, and it along with Hashtable both implement Map interface.
  • HashMap does not guarantee that the order of the map will remain constant over time.

Difference between Java Enumeration and Iterator ?
Both Iterator and Enumeration allows to traverse over elements of Collections. Enumerations do not allow any modification of the collection during its traversal. Iterators on the other hand allow the caller to remove elements from the underlying collection during the iteration with the remove method. Also iterator has shorter method names.

Can static methods be overridden ?
No. Static methods and fields are associated with the class, not with the objects. Overriding depends on having an instance of a class. The point of polymorphism is that the objects implementing the subclasses will have different behaviors for the same methods defined in the superclass. Since static method is not associated with any instance of a class the overriding concept is not applicable. Further we can define class A with method a(), and class B which extends A also with method a(). Since B.a() has the same name as a method in the parent class, it hides A.a(), as the compiler uses the actual class of the declared reference to determine which method to run.

When should we use intern method of String ?
A pool of strings is maintained privately by the class String which is initially empty. When the intern method is invoked, if the pool already contains a string equal to the String object passed as determined by the equals() method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned. All literal strings and string-valued constant expressions are interned. Hence the intern() method is to be used on Strings constructed with new String().

Why String is Immutable in Java ?
String objects are cached in String pool which is maintained privately by the class String for better performance. When a string is created and if the string already exists in the pool, the reference of the existing string will be returned, instead of creating a new object and returning its reference.
Since cached String literal is shared between multiple clients there is always a security risk, when one client's action would affect all other clients. Also string is widely used for network connection, opening files etc and mutable strings can pose a big security threat. Hence String is immutable. Also string is made final so that no one can compromise invariant of String class e.g. Immutability, Caching, Hashcode etc by overriding its behavior. Since string is immutable, it is thread-safe and it caches its hashcode instead of calculating it every time for better performance e.g. in Hashmap.

What is the difference between LinkedList and ArrayList ?
LinkedList and ArrayList are two different implementations of the List interface. LinkedList implements it with a doubly-linked list while ArrayList implements it with a dynamically resizing array. LinkedList allows for constant-time insertions or removals using iterators, but only sequential access of elements. Hence finding a position in the LinkedList takes time proportional to the size of the list. ArrayList allow fast random read access to any element in constant time, although adding or removing elements from anywhere but the end requires shifting all the latter elements over, either to make an opening or fill the gap. Also, if more elements are added than the capacity of the underlying array, a new array (1.5 times the size) is allocated, and the old array is copied to the new one, adding to an ArrayList is O(n) in the worst case.

How does Java Garbage Collection works ?
The operating system allocates the heap in advance to be managed by the JVM while the program is running. Object creation is faster because global synchronization with the operating system is not needed for every single object. An allocation claims some portion of a memory array and moves the offset pointer forward for the next allocation.

Java Garbage Collector tracks the live objects and everything else is designated to be garbage collected. When an object is no longer used, the garbage collector reclaims the underlying memory and reuses it for future object allocations. All objects are allocated on the heap area managed by the JVM. As long as an object is being referenced, the JVM considers it alive. Once an object is no longer referenced and therefore is not reachable by the application code, the garbage collector removes it and reclaims the unused memory. Hence any instances that cannot be reached by a live thread, or Circularly referenced instances that cannot be reached by any other instances handled by the Garbage collector.

Every object tree must have one or more root objects. Special objects called garbage-collection roots are always reachable and so is any object that has a garbage-collection root at its own root.
The garbage collection usually runs the mark-and-sweep algorithm which carries out two step process. The algorithm traverses all object references, starting with the GC roots, and marks every object found as alive. All of the heap memory that is not occupied by marked objects is reclaimed. It is simply marked as free, essentially swept free of unused objects.
Garbage collection intends to remove the cause of classic memory leaks were unreachable-but-not-deleted objects in memory.

The Garbage collection process cannot be forced, but can be requested to the JVM to initiate the Garbage Collection process using System.gc() and Runtime.gc(). The JVM can reject such request as it is not guaranteed to initiate garbage collection on such requests.

Before evicting an instance and reclaiming the memory space, the Java garbage collector invokes the finalize() method of the respective instance so that the instance will get a chance to free up any resources held by it. Though there is a guarantee that the finalize() will be invoked before reclaiming the memory space, there is no order or time specified. The order between multiple instances cannot be predetermined, they can even happen in parallel. Programs should not per-mediate an order between instances and reclaim resources using the finalize() method.

Any uncaught exception thrown during finalize process is ignored silently and the finalization of that instance is cancelled.  Hence it will never be called more than once on an object (by the JVM).
Garbage collection runs behind the application by a daemon thread, initiated by the JVM.

There are different types of references in Java
-----------------------------------------------------------------------------------------
Reference                       Garbage Collection
-----------------------------------------------------------------------------------------
Strong Reference           Not eligible for garbage collection
Soft Reference               Garbage collection possible but will be done as a last option
Weak Reference             Eligible for Garbage Collection
Phantom Reference        Eligible for Garbage Collection
-----------------------------------------------------------------------------------------
When a GC happens it is necessary to completely pause the threads in an application whilst collection occurs. This is known as Stop The World.  For most applications long pauses are not acceptable.  As a result it is important to tune the garbage collector to minimize the impact of collections to be acceptable for the application.

Most applications have a high volume of short lived objects.  Analyzing all objects in an application during a GC would be slow and time consuming, so it therefore makes sense to separate the shortlived objects so that they can be quickly collected. Hence the new generation heap is split into Eden Space and Survivor spaces. The New Generation helps to reduce the impact of fragmentation.

Eden Space: All new objects are placed in eden space.  When it becomes full, a minor GC occurs.  All objects that are still referenced are then promoted to a survivor space.

Survivor spaces: Each GC of the New Generation increments the age of objects in the survivor space.  When an object has survived a sufficient number of minor GCs (normally start at 15) it will then be promoted to the Old Generation.  Some implementations use two survivor spaces, a From space and a To space. During each collection these will swap roles, with all promoted Eden objects and surviving objects move to the To space, leaving From empty.

Any objects survived from survivor spaces in the New Generation are promoted to the Old Generation. The Old Generation is usually much larger than the New Generation.  When a GC occurs in old gen it is known as a full GC. Full GCs are also stop-the-world and tend to take longer, which is why most JVM tuning occurs here.

When should we use a volatile variable ?
In a multi-threaded environment, the changes made by multiple threads on instance variables is not visible to others in absence of any synchronizers, were the volatile variable comes into picture. The copy of volatile variable is stored in the main memory, so every time a thread access the variable even for reading purpose the local copy is updated each time from the main memory. The volatile variable also has performance issues.

What is the difference between yield() and sleep() ?
The yield() method causes the current thread to transit from running to ready-to-run state thus relinquish the CPU and giving other threads in ready-to-run state a chance to run. It only guarantees that current thread will relinquish the CPU but doesn't say anything about which other thread will get CPU. The current thread is at the mercy of the thread scheduler as to when it will run again. Its can be possible for same thread to get CPU back immediately. A call to yield() method does not affect any locks that the thread might hold.

The call to sleep() method causes currently running thread to pause its execution and transit to sleeping state. Sleep method does not relinquish any lock that the thread might have. The thread will sleep with the amount of time specified in its argument and then transition to ready-to-run state where it takes its turn to run again.

What is difference between wait(), notify() and notfiyAll() ?
The wait and notify methods provide means of communication between threads that synchronize on the same object.
The wait() method allows thread to release the lock and goes to suspended (waiting-for-notification) state. The thread is only active when a notify() or notifAll() method is called for the same object.

The notify() method will only notify one Thread and notifyAll() method will notify all Threads which are waiting on that monitor or lock. When notify method is called only one of waiting thread will be woken, but its not guaranteed which thread will be woken as it depends upon JVM implementation. The notifyAll method on other hand wakes up all the threads waiting on the lock, but again all woken thread will fight for lock before executing remaining code. Hence wait method is usually called within a loop because if multiple threads are woken up, the thread which gets the lock first will execute and it may reset waiting condition, which will force subsequent threads to wait. On being notified, a waiting thread first transits to the Blocked-for-lock-acquisition state to acquire the lock on the object, before transitioning to Ready-to-Run state. When the notified thread executes, the call to the wait() method returns and the thread can continue with its remaining execution.

In order to call the wait (), notify () or notifyAll () methods in Java, we must have obtained the lock for the object on which we're calling the method. If wait(), notify() or notifyAll() methods are not called from synchronized context then an IllegalMonitorStateException is thrown.

The wait() method releases the lock prior to waiting and reacquires it prior to returning from the wait() method. Hence the lock must be used to ensure the checking and setting of the condition is atomic, which can only be achieved by using synchronized method or block. Further even if after waking up the thread by calling notify method, the awakened thread will not be able to proceed until the current thread relinquishes the lock on object.

What is the difference between Runnable and Callable interface ?
The Callable interface is similar to Runnable, in that both are designed for classes whose instances are potentially executed by another thread. A Runnable, however, does not return a result and cannot throw a checked exception. Runnable interface has run() method to define task while Callable interface uses call() method for task definition.

When is join() method used ?
A thread can invoke a join() method on another thread in order to wait for the other thread to complete its execution before continuing. The thread calling join waits until other thread completes its execution, or waiting thread is time out or interrupted.

Why should we use ReentrantLock instead of synchronized ?
ReentrantLock supports lock polling, and interruptible lock waits that support time-out. ReentrantLock also has support for configurable fairness policy, allowing more flexible thread scheduling. The timed and polled lock-acquisition allows to regain control if we cannot acquire all the required locks, release the ones already acquired and retry. The tryLock() method makes an attempt to acquire all the locks, if it cannot then it releases the acquired locks (thus preventing deadlock) and retries again. It supports non-block Structured Locking were a lock is always released in the same basic block in which it was acquired using intrinsic locks, regardless of how control exits the block. Interruptible Lock acquisition allows us to try and acquire a lock while being available for interruption. The thread hence can immediately react to the interrupt signal sent to it from another thread. This is helpful to send a KILL signal to all the waiting locks. The ReentrantLock provides options to create a non-fair lock or a fair lock. With fair locking, threads can acquire locks only in the order in which they were requested, whereas an unfair lock allows a lock to acquire it out of its turn, thus breaking the queue and acquiring the lock when it became available.

What is a Daemon thread ?
A daemon thread is a thread whose execution state is not evaluated when the JVM decides if it should stop or not. The JVM stops when all user threads (in contrast to the daemon threads) are terminated. A user thread cannot be converted into a daemon thread once it has been started. Invoking the method thread.setDaemon(true) on an already running thread instance causes a IllegalThreadStateException.

Can a constructor be synchronized ?
No, a constructor cannot be synchronized. The reason why this leads to an syntax error is the fact that only the constructing thread should have access to the object being constructed.

Is it possible to check whether a thread holds a lock on the given object ?
The class java.lang.Thread provides the static method Thread.holdsLock(Object) that returns true if the current thread holds the lock on the object, given as argument to the method invocation.

What is the purpose of the class java.lang.ThreadLocal ?
As memory is shared between different threads, ThreadLocal provides a way to store and retrieve values for each thread separately. Implementations of ThreadLocal store and retrieve the values for each thread independently in the same instance of ThreadLocal. Instances of ThreadLocal can be used to transport information throughout the application without the need to pass them from method to method.

What is Compare-And-Swap and which Java classes use it ?
Compare-And-Swap (CAS) means that the processor provides a separate instruction that updates the value of a register only if the provided value is equal to the current value. CAS operations are used to avoid synchronization were the thread tries to update a value by providing its current value and the new value to the CAS operation. If another thread has meanwhile updated the value, the thread’s value is not equal to the current value and the update operation fails. The thread then reads the new value and tries again. Hence the necessary synchronization is interchanged by an optimistic spin waiting. The java.util.concurrent.atomic provides AtomicInteger or AtomicBoolean which internally use the CAS operation to implement concurrent incrementation.

What is a Semaphore ?
A semaphore is a data structure that manages a set of permits that have to be acquired by competing threads. Semaphores is used to control how many threads access a critical section or resource simultaneously. The constructor of java.util.concurrent.Semaphore takes the initial number of permits the threads compete about. Each invocation of its acquire() methods tries to obtain one of the available permits. The method acquire() without any parameter blocks until the next permit gets available. When the thread has finished its work on the critical resource, it can release the permit by invoking the method release() on an instance of Semaphore. Semaphores are useful for implementing resource pools such as database connection pools.

What is a CountDownLatch ?
The CountDownLatch class provides a synchronization aid that can be used to implement scenarios in which threads have to wait until some other threads have reached the same state such that all thread can start. This is done by providing a synchronized counter that is decremented until it reaches the value zero. Having reached zero the CountDownLatch instance lets all threads proceed. This can be either used to let all threads start at a given point in time by using the value 1 for the counter or to wait until a number of threads has finished. In the latter case the counter is initialized with the number of threads and each thread that has finished its work counts the latch down by one.

What is the difference between a CountDownLatch and a CyclicBarrier ?
Both classes maintain internally a counter that is decremented by different threads. The threads wait until the internal counter reaches the value zero and proceed from there on. But in contrast to the CountDownLatch the class CyclicBarrier resets the internal value back to the initial value once the value reaches zero. As the name indicates instances of CyclicBarrier can therefore be used to implement use cases where threads have to wait on each other again and again.

Tuesday, April 21, 2015

Java Collections

Iterable defines the contract  and foreach statement. Iterable also provides a uniform way of accessing collection elements sequentially.

Collection contains the core functionality required of any collection other than a map.
Set is a collection, without duplicates. Sorted Set automatically sorts its elements and returns them in order.
NavigableSet extends Sorted Set by adding methods to find the closest matches to a target element.
Queue is a collection designed to accept elements at its tail for processing, yielding them up at its head in the order in which they are to be processed.
Deque extends Queue by allowing elements to be added or removed at both head and tail.
BlockingQueue and BlockingDeque are subinterfaces of Queue and Deque, and support concurrent access and block threads indefinitely or till timeout, until the requested operation can be carried out.
List is a collection in which order is significant, accommodating duplicate elements.
Map is a collection which uses key-value associations to store and retrieve elements. It is extended by ConcurrentMap, which provides support for concurrent access, by SortedMap, which guarantees to return its values in ascending key order, by Navigable-Map which extends SortedMap to find the closest matches to a target element, and by ConcurrentNavigableMap which extends ConcurrentMap and NavigableMap.

The Collections class provides wrapper objects that modify the behavior of standard collections classes in one of three ways—by synchronizing them, by making them unmodifiable, or by checking the type of elements being added to them.

Iterators of collections throw ConcurrentModificationException whenever they detect that the collection from which they were derived has been structurally changed i.e. elements have been added or removed. Iterators are implemented as a view of their underlying collection so, if that collection is structurally changed, the iterator may well not be able to continue operating correctly when it reaches the changed part of the collection. The policy of iterators for collections is fail fast.
Note: Using the iterator to iterate the collection and trying to remove the element using the collection's remove() method still throws ConcurrentModificationException. The remove() method of the iterator itself should only be used to avoid any exceptions.

Arrays: Arrays provide random-access memory with fast element access by position but slow insertion or removal of elements. They are used as the backing structure for ArrayList, CopyOnWriteArrayList, EnumSet and EnumMap, and for many of the Queue and Deque implementations.

Linked lists: It consist of chains of linked cells, cell containing data and reference to next cell in the list. Accessing elements by position is slow, but insertion and removal operations can be performed in constant time.

Hash tables: It stores elements indexed on their content rather than on an integer-valued index. Hash tables are the backing structure
for many Set and Map implementations, including HashSet and LinkedHashSet together with the corresponding maps HashMap and LinkedHashMap.

Trees: It organizes the elements by content and can store or retrieve them in sorted order. Trees are the backing structures for TreeSet and TreeMap.

Adding an element to the end of an ArrayList can normally be done in constant time, unless the ArrayList has reached its capacity. In such case, a new and larger array must be allocated, and the contents of the old array transferred into it. The cost of this operation is linear in the number of elements in the array, but its occurrence is relatively rare. The amortized cost is the total cost of performing the operation n times divided by n, taken to the limit as n becomes arbitrarily large. Hence amortized cost of adding an element to an ArrayList is, the total cost for N elements is O(N), so the amortized cost is O(1).

Some Collection API methods return collections with restricted functionality. The set of keys obtained from a Map can have elements removed but not added. Others e.g. the list view returned by Arrays.asList can have elements neither added nor removed or may be completely read-only.

Thread Safety: Legacy collections can be made thread safe by synchronizing the critical section of code. Before a thread can execute synchronized code, it has to get the lock on the current object. Any other thread trying to enter critical section will be blocked on the lock and suspended until the lock is released. The concurrent collections achieve thread safety by using copy-on write, compare-and-swap and concurrent locks.

Copy-on-Write: Classes that use copy-on-write store their values in an internal array, which is effectively immutable; any change to the value of the collection results in a new array being created to represent the new values. Copy-on-write is used by the collection classes CopyOnWriteArrayList and CopyOnWriteArraySet.

Compare-and-Swap (CAS): Consider a computation were the value of a single variable is used as input to a long-running calculation whose eventual result is used to update the variable. In CAS, it makes a local copy of the variable and performs the calculation without getting exclusive access. Only when it is ready to update the variable does it call CAS, which in one atomic operation compares the variable’s value with its value at the start and, if they are the same, updates it with the new value. If they are not the same, the variable must have been modified by another thread. Collections using CAS include ConcurrentLinkedQueue and ConcurrentSkipListMap.

Concurrent Locks: A thread can acquire locks under special conditions, only if the lock is not currently held, or with a timeout, or if the thread is not interrupted. Unlike synchronized code, in which an object lock is held while a code block or a method is executed, a Lock is held until its
unlock method is called. Hence collection can be divided into parts so that they can be separately locked, giving improved concurrency. LinkedBlockingQueue and ConcurrentHashMap are collections using locks.

Set: A set is a collection of items that cannot contain duplicates; adding an item if it is already present in the set has no effect.

HashSet: It is implemented by a hash table, an array in which elements are stored at a position derived from their contents. An element’s position in a hash table is calculated by a hash function of its contents. Hash functions are designed to give, as far as possible, an even spread of results (hash codes) over the element values that might be stored. Collections Framework classes use bit masking to obtain an index from the hash code.
When two distinct values hash to the same location in the hash table, collisions occur in hashing. When collisions do occur, we have to have a way of keeping the colliding elements at the same table location or bucket, often done by storing them in a linked list.

HashSet is actually implemented by a specialized HashMap, each of the cells in the chain contains not one but two references, to a key and a value. When a hash table is being used to represent a set, all values are the same, only the presence of the key is significant.

If a collision does take place, a linked list has to be created and subsequently traversed, adding an extra cost to insertion proportional to the number of elements in the list. The table size is increased by rehashing—copying to a new and larger table—when the load reaches a specified threshold (its load factor) to avoid worsening of performance.

Iterating over a hash table requires each bucket to be examined to see whether it is occupied and therefore costs a time proportional to the capacity of the hash table plus the number of elements it contains. Since the iterator examines each bucket in turn, the order in which elements are returned depends on their hash codes, so there is no guarantee as to the order in which the elements will be returned.

The chief attraction of a hash table implementation for sets is the (ideally) constanttime performance for the basic operations of add, remove, contains, and size. Its main disadvantage is its iteration performance; since iterating through the table involves examining every bucket, its cost is proportional to the table size regardless of the size of the set it contains.
HashSet is unsychronized and not thread-safe; its iterators are fail-fast.

LinkedHashSet: It uses a doubly linked list internally and a hash table. LinkedHashSet inherits from HashSet and guarantees that its iterators will return their elements in the order in which they were first added. It does this by maintaining a linked list of the set elements.



The linked structure has an improved performance for iteration, were the next performs in constant time, as the linked list can be used to visit each element in turn. It is in contrast to HashSet were every bucket in the hash table must be visited whether it is occupied or not, but adds the overhead of maintaining the linked list. LinkedHashSet is chosen in preference to HashSet only if the order or the efficiency of iteration is more important. LinkedHashSet is unsychronized and not threadsafe and its iterators are fail-fast.

CopyOnWriteArraySet: It is implemented as a thin wrapper around an instance of CopyOnWriteArrayList, which in turn is backed by an array. The array is treated as immutable; any change to the contents of the set results in an entirely new array being created. Hence add or contains operations has complexity O(n) as its implemented by a linear search. CopyOnWriteArraySet should not be used were many searches or insertions are expected. The backing array implementation means that iteration costs O(1) per element faster than HashSet, and it provides thread safety without adding any cost for read operations. Commonly used in  Subject-Observer design pattern requiring events to be notified to a set of observers. This set must not be modified during the process of notification; which is ensured by CopyOnWriteArraySet with the overhead carried entirely by write operations. Iterators are only allowed to read the set and remove method is not implemented, thus called snapshot iterators.
CopyOnWriteArraySet should only be used where set size will remain relatively small, read operations greatly outnumber writes and thread safety is required.

EnumSet: Implementation were the number of possible elements is fixed and a unique index can be assigned to each elements. The number of keys is fixed by the constants of the enumerated type, and the ordinal method returns values that are guaranteed to be unique to each constant. The add, remove, and contains methods are implemented as bit manipulations, with constant-time performance. Bit manipulation on a single word is extremely fast, and a long value can be used to represent EnumSets over enum types with up to 64 values. EnumSet is an abstract class and it hides the concrete implementation by exposing factory methods that call the constructor for the appropriate subclass.

EnumSet obeys the contract for Set, with the added specification that its iterators will return their elements in the order in which their enum constants are declared. It is not thread-safe and its iterators are not fail-fast. They may be either snapshot or weakly consistent; but the contract guarantees only that they will be weakly consistent.

SortedSet and NavigableSet: It is a subinterface of Set which adds to the Set contract a guarantee that its iterator will traverse the set in ascending element order. TreeSet is the only implementation of SortedSet. Merging two sorted lists of size n is O(n), but adding n elements to a TreeSet of size n is O(n log n). The SortedSet uses the compare method of its Comparator or, if its not present then the compareTo method of its elements is used instead of the elements equals method to determine when elements are distinct.
NavigableSet interface extends SortedSet and adds methods to find the closest matches to a target element. The NavigableSet methods (especially for getting range views, e.g subSet, tailSet etc) allow to specify for each bound whether it should be inclusive or exclusive. NavigableSet returns null values to signify the absence of elements.

TreeSet: Trees are the data structure which provides fast insertion and retrieval of individual elements but which also requires that they be held in sorted order. Trees perform better than list but are slower than hash tables. Their advantage over hash tables being the capability to maintain the ordering or sortedness. The cost of retrieving or inserting an element is proportional to the depth of the tree, since we locate the word by alphabetic comparison at each level starting from the root. A binary tree with n complete levels will have 2n–1 elements. Hence the depth of a tree with n elements will be bounded by log n (since 2^log n = n).

TreeSet uses a data type called a red-black tree, which has the advantage that if it becomes unbalanced through insertion or removal of an element, it can always be rebalanced in O(log n) time. TreeSet is unsychronized and not thread-safe; its iterators are fail-fast.

ConcurrentSkipListSet: It is backed by a skip list, a modern alternative to the binary trees. A skip list for a set is a series of linked lists, each of which is a chain of cells consisting of two fields: one to hold a value, and one to hold a reference to the next cell. Elements are inserted into and removed from a linked list in constant time by pointer rearrangement.

The first linked list of the collection (level 0 in the figure) contains the elements of the set, sorted according to their natural order or by the comparator of the set. Each list above level 0 contains a subset of the list below, chosen randomly according to a fixed probability. For this example, if the probability is 0.5 on average then each list will contain half the elements of the list below it. Navigating between links takes a fixed time, so the quickest way to find an element is to start at the beginning of the top list and to go as far as possible on each list before dropping to the one below it, when the next element is higher than the search value. Elements are removed from skip list by removing it from each level in which it occurs.




The probability is very high that skip lists will give performance comparable to binary trees: search, insertion and removal all take O(log n). Their compelling advantage for concurrent use is that they have efficient lock-free insertion and deletion algorithms, whereas there are none known for binary trees. The iterators of ConcurrentSkipListSet are weakly consistent.



The HashSet, LinkedHashSet and TreeSet are not thread safe, hence should be wrapped in Collection.synchronizedSet for multi-threading. Both HashSet and LinkedHashSet have no sorting. If require frequently iterating over the set or access ordering LinkedHashSet is the choice. If the set should sort its elements then TreeSet and ConcurrentSkipListSet should be use.
 
Queue: It is a collection to process elements by first in first out basis. Below are the methods included in Queue interface.
boolean add(E e);        // throws exception if currently out of space
boolean offer(E e);        // throws exception if unable to insert (preferable)
E remove();                // removes and returns head, exception if queue is empty
E poll();                // removes and returns head, 'null' if queue is empty
E element();            // returns head, exception if queue is empty
E peek();                // returns head, 'null' if queue is empty

In general, the use of null as a queue element is discouraged by the Queue interface as peek() and poll() methods return null for empty queue, and LinkedList is only standard implementation that allows it. Queue implementation varies mainly with the ordering of retriving the elements.

ArrayDeque: It is used get FIFO ordering and is unbounded.
PriorityQueue: It processes its elements according to the ordering either natural if implement Comparable or custom if implemented by Comparator. It is not thread safe, nor provides blocking behavior. Priority Queue gives no guarantee of how it presents multiple elements with the same value. Priority queues are implemented by priority heaps which is a binary tree similar to TreeSet with two differences.

First constraint is the only ordering constraint is that each node in the tree should be larger than either of its children, and second, that the tree should be complete at every level except possibly the lowest; if lowest level is incomplete, the nodes it contains must be grouped together at the left.
The new element is added to the leftmost vacant position and then it is repeatedly exchanged with its parent until it reaches a parent that has higher priority. When root element with highest priority is removed, it first places the rightmost element from the bottom row into the root position and reverses the add process by repeatedly exchanging with the larger of its children until it has highest priority. Addition and Removal require minimum operations proportional to height of the tree, hence add, remove takes O(log n) time, while contains takes O(n) as it traverses entire tree.

ConcurrentLinkedQueue: It is an unbounded, thread-safe, FIFO-ordered queue. It uses a linked structure. It uses a CAS-based wait-free algorithm—that is, one that guarantees that any thread can always complete its current operation, regardless of the state of other threads accessing the queue. It executes queue insertion and removal operations in constant time, but requires linear time to execute size, as the algorithm relies on co-operation between threads for insertion and removal and does not keep track of the queue size.

BlockingQueue: Primarily used for producer-consumer queues, and ensuring that enqueue and dequeue do not return until they have executed successfully. BlockingQueue methods come in four forms as below, one throws an exception, the second returns a special value (either null or false, depending on the operation), the third blocks the current thread indefinitely until the operation can succeed, and the fourth blocks for only a given maximum time limit before giving up.

Queue Methods Summarization
Throws exception Special value Blocks Times out
Insert add(e) offer(e) put(e) offer(e, time, unit)
Remove remove() poll() take() poll(time, unit)
Examine element() peek() not applicable not applicable

BlockingQueue guarantees that the queue operations of its implementations will be threadsafe and atomic. But this guarantee doesn’t extend to the bulk operations inherited from Collection—addAll, containsAll, retainAll and removeAll. The five BlockingQueue implementations are LinkedBlockingQueue, ArrayBlockingQueue, PriorityBlockingQueue, DelayQueue and SynchronousQueue.

LinkedBlockingQueue: It is a thread-safe, FIFO-ordered queue, based on a linked node structure. Its choice for an unbounded blocking queue, and better than ArrayBlockingQueue for bounded use. Insertion and removal requires constant time while contains require linear time. Iterators are weakly consistent.

ArrayBlockingQueue: Implementation is based on a circular array. Only the elements at the front and rear could be removed at constant time using the head or the tail of the queue. Insertion and removal of elements in the middle of the queue has time complexity O(n) as all the elements from one end must be moved along to maintain a compact representation. Its constructors provide a collection parameter to be initialized with the contents of the specified collection with the same order. They also provide the alternative to provide a fair scheduling policy which guarantees that the queue will choose the one that has been waiting longest. Ordering is FIFO, insertion and removal requires constant time while contains require linear time. Iterators are weakly consistent.

PriorityBlockingQueue: It is a thread-safe, blocking version of PriorityQueue. Its iterators are failfast.

DelayQueue: Its a specialized priority queue, were ordering is based on the delay time for each element i.e. he time remaining before the element will be ready to be taken from the queue. If all elements have a positive delay time, then poll will return null. The element with the longest-expired delay time will be at the head of the queue. Most queue operations treat a queue with no unexpired elements as if it were empty except for peek and remove.

SynchronousQueue: This queue has no internal capacity. A thread that wants to add an element to a SynchronousQueue must wait until another thread is ready to simultaneously take it off, and same is true for the reverse case. It has a mechanism for synchronizing two threads, allowing them to cooperate by exchanging data. SynchronousQueue behaves like an empty Collection and returns an empty iterator.

Deque: A double-ended queue can insert or remove elements from either end, unlike a queue were insertion can only occur at the rear and removal at rear.
It is a linear structure in which elements added at the tail are yielded up in the same order at the head. It has methods, addFirst and addLast similar to push, removeFistOccurence similar to remove in Collection, offerFirst similar to offer in Queue.

ArrayDeque: It uses a circular array and similar to ArrayBlockingQueue. It can be used as deques and FIFO queues. Add and remove at head/tail take constant time and its iterators are failfast.

LinkdList: Its only implementation of Deque permitting null elements. It has linked list structure and extra field in each cell to point to the previous entry to enable backward traversal. Its advantage is constant insertion and removal time, and its iterators are fail fast.

BlockingDeque: Similar to BlockingQueque adding similar methods for operations at the other end of Deque. Concurrent deques are the basis of one of the best load balancing methods, work stealing (were an idle thread can process tail elements in parallel when head is processed by a thread).
It is implemented based on a doubly linked list structure similar to LinkedList. Queue insertion and removal take constant time and operations such as contains, which require traversal of the queue, require linear time. The iterators are weakly consistent.

 


Lists: A list is a collection which—unlike a set—can contain duplicates, and which—unlike a queue—gives the user full visibility and control over the ordering of its elements. It includes methods for positional access, search, range view. The subList() method works in a similar way to the subSet(), were it returns a view of part of the list from which it was obtained, so changes in it are reflected in the original list. If elements are modified in the backing list then any later attempts to use subList results ins ConcurrentModificationException.

ArrayList: ArrayList is a List backed by array and is resizable and extensible. When ArrayList grows to the point where its size is equal to its capacity, an attempt add another element leads to replace the backing array with larger one holding old contents and new element, which makes its amortized cost to O(1). The get and set operations takes constant time, while add and remove require adjusting other elements, and hence proportional to size of the list. ArrayDeque provides better insertion and removal performance than ArrayList, along with random access as its implemented using circular queue. The initial capacity of an ArrayList created by the default constructor is 10. The iterators of ArrayList are fail-fast.

LinkedList: LinkedList is backed by a doubly linked list and is bad for random access. Adding or Removing just requires link manipulations so is better than ArrayList in that sense. LinkedList takes constant time for adding and removing elements.

CopyOnWriteArrayList: It provides thread safety along with very fast read access. The cost is that the array which backs the collection has to be treated as immutable, so a new copy is created whenever any changes are made to the collection. This cost may not be too high to pay if changes in the set of observer objects occur only rarely. CopyOnWriteArraySet delegates all of its operations to an instance of CopyOnWriteArrayList. If frequent writes are required along with thread safety then a synchronized wrapper is used around ArrayList or LinkedList.



Map: It does not inherit from Collection interface. It defines the operations that are supported by a set of key-to-value associations in which the keys are unique. Map provides methods such as entrySet(), keySet() and values() to return collection views. The collections returned by these methods are backed by the map, so any changes to them are reflected in the map itself, and vice versa. Elements can be removed directly or via an iterator over the view, but cannot be added as will get an UnsupportedOperationException. Removing key removes the key-value association while removing values only removes association mapping it.

HashMap: HashMap has an fixed sized internal array of buckets, each identified by a unique number. HashMap stores both key and value object as Map.Entry in bucket. While adding a key-value pair to HashMap, the hashcode for the key is computed and the pair is stored in the bucket with the identifier equal to hash code of the key. At some point of time hash function will return same bucket location for two different keys known as a collision in HashMap. In such case, a linked list is formed at that bucket location and new entry is stored as next node. In order to retrieve object from this linked list an extra check to search correct value is required which is done by equals() method. Since each node contains an entry, HashMap keep comparing entry's key object with passed key using equals() and when it return true, Map returns corresponding value. The equals() and hashcode() methods are not used in case of null keys in HashMap. HashMap provides constant time performance for put and get. The iterators are fail-fast.

LinkedHashMap: LinkedHashMap refines the contract of its parent class, HashMap, by guaranteeing the order in which iterators return its elements.
In LinkedHashMap iteration; elements can be returned either in the order in which they were inserted in the map, or in the order in which they were accessed (from least to most recently accessed) using the accessOrder constructor flag. Access-ordered maps are especially useful for constructing Least Recently Used (LRU) caches. The removeEldestEntry (method) contract states that the methods put and putAll will call removeEldestEntry whenever a new entry is added to the map, providing the opportunity to remove the eldest entry each time a new one is added. In LinkedHashMap itself, removeEldestEntry does nothing and returns false. Iteration over a collection of keys or values returned by a LinkedHashMap is linear in the number of elements. The iterators over such collections are fail-fast.

WeakHashMap: An ordinary Map keeps ordinary (“strong”) references to all the objects it contains. But suppose that the objects of the key class are unique—that is, object equality is the same as object identity e.g. unique serial number. In this case, once we no longer have a reference—from outside the map—to an object being used as a key, we can never look it up again, because we can never re-create it. So the map might as well get rid of the key-value pair and conserve memory, which is the idea of WeakHashMap. Internally WeakHashMap holds references to its key objects through references of the class java.lang.ref.WeakReference. A WeakReference introduces an extra level of indirection in reaching an object. For example, weak reference to the string "code gui" is made as below:
WeakReference<String> wref = new WeakReference<String>("code gui");
And at a later time we would recover a strong reference to it using the get method of WeakReference, e.g. weakRef.get(). As weak reference does not prevent garbage collector from reclaiming the object, the recovered reference may or may not be null. Only strong references are followed to determine reachability, so the keys of a WeakHashMap will be available to be reclaimed if they are not reachable by any other route by garbage collector. A key cannot be reclaimed if it is strongly referenced from the corresponding value. Before most operations on a WeakHashMap are executed, the map checks which keys have been reclaimed, without just checking null keys as null is valid value for the key in WeakHashMap. The WeakReference mechanism allows us to tell the garbage collector to leave information in a ReferenceQueue each time it reclaims a weakly referenced object. The WeakHashMap then removes every entry of which the garbage collector has reclaimed the key.
Its drawbacks is that it weakly references the map’s keys rather than its values, which usually occupy much more memory, hence until stale entries are not removed from map the memory benefit is limited. The second drawback is that weak references are too weak; the garbage collector is liable to reclaim a weakly reachable object at any time, and the programmer cannot influence this in any way. The iterators are fail fast.

IdentityHashMap: In IdentityHashMap, two keys are considered equal only if they are physically the same object: identity, rather than equals, is used for key comparison. IdentityHashMap is a specialized class, commonly used in operations such as serialization. The algorithm which traverses the graph be able to check for each node, whether that node has already been seen; to detect graph cycles. Collisions are handled by linear probing, a technique in which the key and value references are stored directly in adjacent locations in the table itself rather than in cells referenced from it. With linear probing, collisions are handled by simply stepping along the table until the first free pair of locations is found.

EnumMap: Similar to EnumSet were in an array implementation, the ordinal value of each enumerated type constant can serve as the index of the corresponding value. Read and write operations takes constant time. It is not thread-safe and iterators are weakly consistent.
An EnumMap contains a reified key type used to check validity of new entries.

SortedMap: SortedMap adds to its contract a guarantee that its iterators will traverse the map in ascending key order. A SortedMap imposes an ordering on its keys, either that of their natural ordering or of a Comparator, were compare should be consistent with equals method.

NavigableMap: NavigableMap extends SortedMap. It returns result of type Map.Entry. Map.Entry objects returned by its methods are snapshot objects reflecting the state of
the map at the time they were produced, and do not support setValue.

TreeMap: SortedMap is implemented in the Collections Framework by TreeMap. The internal representation of a TreeSet is just a TreeMap in which every key is associated with the same standard value. Its basic operations (get, put, and remove) perform in O(log n) time). The collection view iterators are fail-fast.

ConcurrentMap: Collections.synchronizedMap does not provide high-throughput thread-safety because with full synchronization
each operation needs to obtain an exclusive lock on the entire map. Locking only a part of the collection at a time—lock striping—
can achieve very large gains in throughput. Clients need assistance from the collection itself to carry out atomic actions as there is no single lock for a client to hold to gain exclusive access.

ConcurrentHashMap: Its an implementation of ConcurrentMap providing throughput with thread safety. The contract states that the results of retrievals will reflect the latest update operations completed before the start of the retrieval. Updates also can often proceed without blocking, because a ConcurrentHashMap consists of not one but a set of tables, called segments, each of which can be independently locked. If the number of segments is large enough relative to the number of threads accessing the table, there will often be no more than one update in progress per segment at any time.
The constructor allows to provide the number of segments that the map will use to control its concurrency level. THe size() method obtains an exclusive lock to all the segments, obtaining the entry count from each, then unlocking them again. The collection views return weakly
consistent iterators.

ConcurrentNavigableMap: It inherits from both ConcurrentMap and NavigableMap, and contains just the methods of these two interfaces with a few changes to make the return types.

ConcurrentSkipListMap: It is similar to ConcurrentSkipListSet and implemented by a ConcurrentSkipListMap in which every key is associated with the same standard value. Basic operations (get, put, and remove) perform in O(log n) time); iterators over the collection views execute next in constant time.