17. Collection Name
|
java.util.Collections.synchronizedMap
|
Implementation
Of
|
implements Map<K,V>, Serializable
|
Is
Ordered
|
Yes
|
Is
Resizable
|
Yes
|
Is
Thread Safe
|
Yes
|
Duplicate
allowed
|
A map cannot contain duplicate keys
|
Null
allowed
|
Null keys are not permitted. Null values are
permitted.
|
Iterate
Logic
|
entry set iterator
|
Complexity
|
|
More
info
|
ü
All method calls on the collection are
synchronized. Only one thread will be allowed to read/modify the collection
at a time.
ü
So there is much less chances to make a
mistake if you use synchronized collection instead of doing all
synchronization stuff by yourself.
ü Map<String,String>
synmap = Collections.synchronizedMap(map);
ü The
synchronized collection protects itself from multiple threads corrupting the
map itself. It does not protect against logic race conditions around multiple
calls to the map like below.
synchronized (synchronizedMap)
{
// test for a key in the map
if (synchronizedMap.containsKey(key)) {
synchronizedMap.get(key).add(value);
} else {
List<String> valuesList = new
ArrayList<String>();
valuesList.add(value);
// store a value into the map
synchronizedMap.put(key, valuesList);
}
}
if you don't synchronize
block/method, assume there may be case like Thread1 executing first part and
thread2 executing second part, your business operation may results in weird
results (even though updates to map are synchronized)
ü Collections.synchronizedMap(map)
creates a blocking Map which will degrade performance, albeit ensure
consistency (if used properly).
ü Becomes
a big problem when you need to iterate over the entire Map, which can take a
long time for a large Map - while one thread does that, all others have to
wait if they want to insert or lookup anything.
ü Map
m = Collections.synchronizedMap(new HashMap());
Set returned by m.keySet() also a
synchronized
SynchronizedSet uses the same mutex which SynchronizedMap returned
by Collections.synchronizedMap(new HashMap()); is using.
Set s = m.keySet();
public Set<K> keySet() {
synchronized (mutex) {
if (keySet==null)
keySet = new
SynchronizedSet<>(m.keySet(), mutex);
return keySet;
}
}
ü
synchronizedMap is just a wrapper. It wraps
all data access functions of underlying Map and makes them thread safe
|
18. Collection Name
|
java.util.Collections.TreeMap
|
Implementation
Of
|
extends AbstractMap<K,V>
implements NavigableMap<K,V>,
Cloneable, Serializable
|
Is
Ordered
|
Sorted
|
Is
Resizable
|
Yes
|
Is
Thread Safe
|
NO.
can use Collections.synchronizedSortedMap
|
Duplicate
allowed
|
A map cannot contain duplicate keys
|
Null
allowed
|
Null keys are not permitted. Null values are
permitted.
|
Iterate
Logic
|
entry set iterator
|
Complexity
|
Read/Search any element O(log n)
Update : O(log n)
Delete : O(log n)
Add : O(log n)
|
More
info
|
ü
Red-Black tree based NavigableMap
implementation.
ü
The map is sorted according to the natural ordering of its keys, or by a Comparator provided at map creation
time, depending on which constructor is used.
ü
Natural" ordering is the ordering implied
by the implementation of the Comparable interface by the objects used as keys
in the TreeMap. Essentially, RBTree must be able to tell which key is smaller
than the other key, and there are two ways to supply that logic to the RBTree
implementation:
ü
Implement Comparable interface in the
class(es) used as keys to TreeMap, or
ü
Supply an implementation of the Comparator
that would do comparing outside the key class itself.
ü
All keys inserted into the map must implement
the Comparable interface. Furthermore, all such keys must be mutually
comparable
ü
One should use TreeMap only when we have a
large data and need frequent search operation
ü
TreeMap uses a binary tree organization that
gives balanced trees, so O(log2N) is the worst case lookup time.
ü
Using TreeMap and TreeSet work properly when
compareTo and equals are implemented in such a way that they are compatible
with each other. Furthermore, when searching in a Map, only the search for
the key will be efficient (for a TreeMap O(log n)). When searching for a
value in a Map, the complexity will become linear.
ü
There is a way to optimize the search in the
inner TreeSet though, when implementing your own Comparator for the Element
type. This way you can implement your own compareTo method without changing
the Element object itself.
|
package
com.study.collection;
import
java.util.Comparator;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
public class TreeMapDemo {
/**
*
@param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
TreeMap<String, String> tree
= new TreeMap<String, String>();
tree.put("4", "A");
tree.put("3", "B");
tree.put("5", "C");
tree.put("7", "D");
for (Map.Entry<String, String> entry :
tree.entrySet()) {
System.out.println("Key = " + entry.getKey() + ", Value =
"
+
entry.getValue());
}
System.out.println("======
headMap method usage ==============");
SortedMap<String, String>
sort = tree.headMap("5");
for (Map.Entry<String, String> entry :
sort.entrySet()) {
System.out.println("Key = " + entry.getKey() + ", Value =
"
+
entry.getValue());
}
System.out.println("======
tailMap method usage ==============");
SortedMap<String, String> sortTail
= tree.tailMap("5");
for (Map.Entry<String, String> entry :
sortTail.entrySet()) {
System.out.println("Key = " + entry.getKey() + ", Value =
"
+
entry.getValue());
}
System.out.println("======
tailMap method usage ==============");
SortedMap<String, String>
subMap = tree.subMap("2", "8");
for (Map.Entry<String, String> entry :
subMap.entrySet()) {
System.out.println("Key = " + entry.getKey() + ", Value =
"
+
entry.getValue());
}
// Sort by value
System.out.println("==========================================");
System.out.println("Sorted by
value ASC = "
+ TreeMapDemo.sortByValues(tree));
}
// How to sort TreeMap by value in desc
public static <K, V extends Comparable<V>> Map<K, V> sortByValues(
final Map<K, V> map)
{
Comparator<K>
valueComparator = new Comparator<K>() {
public int compare(K k1, K k2)
{
int compare =
map.get(k1).compareTo(map.get(k2));
if (compare == 0)
return 1;
else
return compare;
}
};
Map<K, V> sortedByValues = new TreeMap<K,
V>(valueComparator);
sortedByValues.putAll(map);
return sortedByValues;
}
}
o/p
Key = 3, Value = B
Key = 4, Value = A
Key = 5, Value = C
Key = 7, Value = D
====== headMap method
usage ==============
Key = 3, Value = B
Key = 4, Value = A
====== tailMap method
usage ==============
Key = 5, Value = C
Key = 7, Value = D
====== tailMap method
usage ==============
Key = 3, Value = B
Key = 4, Value = A
Key = 5, Value = C
Key = 7, Value = D
===========================================
Sorted by value ASC =
{4=A, 3=B, 5=C, 7=D}
|
19. Collection Name
|
java.util.WeakHashMap
|
Implementation
Of
|
extends AbstractMap<K,V> implements
Map<K,V>
|
Is
Ordered
|
No
|
Is
Resizable
|
Yes
|
Is
Thread Safe
|
NO.
can use Collections.synchronizedSortedMap
|
Duplicate
allowed
|
A map cannot contain duplicate keys
|
Null
allowed
|
Both null values and the null key are
supported.
|
Iterate
Logic
|
entry set iterator
|
Complexity
|
log(n)
|
More
info
|
ü
Hash table based implementation of the Map
interface, with weak keys.
ü
An entry in a WeakHashMap will automatically
be removed when its key is no longer in ordinary use. More precisely, the
presence of a mapping for a given key will not prevent the key from being
discarded by the garbage collector, that is, made finalizable, finalized, and
then reclaimed. When a key has been discarded its entry is effectively
removed from the map, so this class behaves somewhat differently from other
Map implementations.
ü
This class has performance characteristics
similar to those of the HashMap class, and has the same efficiency parameters
of initial capacity and load factor.
ü
The behavior of the WeakHashMap class depends
in part upon the actions of the garbage collector, so several familiar
(though not required) Map invariants do not hold for this class.
ü
Because the garbage collector may discard keys
at any time, a WeakHashMap may behave as though an unknown thread is silently
removing entries. In particular, even if you synchronize on a WeakHashMap
instance and invoke none of its mutator methods, it is possible for the size
method to return smaller values over time, for the isEmpty method to return
false and then true, for the containsKey method to return true and later
false for a given key, for the get method to return a value for a given key
but later return null, for the put method to return null and the remove
method to return false for a key that previously appeared to be in the map,
and for successive examinations of the key set, the value collection, and the
entry set to yield successively smaller numbers of elements.
ü
Each key object in a WeakHashMap is stored
indirectly as the referent of a weak reference. Therefore a key will
automatically be removed only after the weak references to it, both inside and
outside of the map, have been cleared by the garbage collector.
|
package
com.study.collection;
import java.util.HashMap;
import java.util.Map;
import
java.util.WeakHashMap;
public class WeakHashMapDemo {
/**
*
@param args
*
@throws
InterruptedException
*/
public static void main(String[] args) throws InterruptedException {
Map hashMap = new HashMap();
Map weakHashMap = new WeakHashMap();
String keyHashMap = new String("keyHashMap");
String keyWeakHashMap = new String("keyWeakHashMap");
hashMap.put(keyHashMap, "A");
weakHashMap.put(keyWeakHashMap,
"B");
System.gc();
System.out.println("Before: hash
map value:"
+ hashMap.get("keyHashMap") + " and weak
hash map value:"
+ weakHashMap.get("keyWeakHashMap"));
//Make elligible for garbage collection
keyHashMap = null;
keyWeakHashMap = null;
System.out.println("Running
Garbage Collector....");
System.gc();
System.out.println("After: hash
map value:" + hashMap.get("keyHashMap")
+ " and weak hash
map value:"
+ weakHashMap.get("keyWeakHashMap"));
}
}
O/P
Before: hash map
value:A and weak hash map value:B
Running Garbage
Collector....
After: hash map
value:A and weak hash map value:null
|
20. Collection Name
|
java.util. IdentityHashMap
|
Implementation
Of
|
extends AbstractMap<K,V> implements Map<K,V>, Serializable,
Cloneable
|
Is
Ordered
|
No
|
Is
Resizable
|
Yes
|
Is
Thread Safe
|
No.
Collections.synchronizedMap(new IdentityHashMap(...));
|
Duplicate
allowed
|
Two keys k1 and k2 are considered equal if
and only if (k1==k2).
|
Null
allowed
|
|
Iterate
Logic
|
Iterator<Entry<K,V>> i =
entrySet().iterator();
|
Complexity
|
|
More
info
|
ü
This class implements the Map interface with a
hash table, using reference-equality in place of object-equality when
comparing keys (and values).
ü
In other words, in an IdentityHashMap, two
keys k1 and k2 are considered equal if and only if (k1==k2). (In normal Map
implementations (like HashMap) two keys k1 and k2 are considered equal if and
only if (k1==null ? k2==null :
k1.equals(k2)).)
ü
This class is not a general-purpose Map
implementation! While this class implements the Map interface, it
intentionally violates Map's general contract, which mandates the use of the
equals method when comparing objects. This class is designed for use only in
the rare cases wherein reference-equality semantics are required.
ü
HashMap creates Entry objects every time you
add an object, which can put a lot of stress on the GC when you've got lots
of objects. In a HashMap with 1,000 objects or more, you'll end up using a
good portion of your CPU just having the GC clean up entries (in situations
like pathfinding or other one-shot collections that are created and then
cleaned up). IdentityHashMap doesn't have this problem, so will end up being
significantly faster
ü
Its very fast and consume less memory
|
package
com.study.collection;
import
java.util.IdentityHashMap;
public class IdentityHashMapDemo
{
/**
*
@param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
IdentityHashMap map1 = new IdentityHashMap();
String s1 = new String("1");
String s2 = new String("1");
map1.put(s1, "value");
map1.put(s2, "value");
map1.put("2", "value");
map1.put("3", "value");
System.out.println("Map key as
different Object referance value = "
+ map1.size());
IdentityHashMap map2 = new IdentityHashMap();
String s3 = s1;
map2.put(s1, "value");
map2.put(s3, "value");
map2.put("2", "value");
map2.put("3", "value");
System.out.println("Map key as
same object referance value = "
+ map2.size());
}
}
o/p
Map key as different
Object referance value = 4
Map key as same
object referance value = 3
|
21. Collection Name
|
java.util. LinkedHashMap
|
Implementation
Of
|
extends HashMap<K,V> implements
Map<K,V>
|
Is
Ordered
|
Yes, Order of insertion
|
Is
Resizable
|
Yes
|
Is
Thread Safe
|
No
|
Duplicate
allowed
|
A map cannot contain duplicate keys
|
Null
allowed
|
Null keys are not permitted. Null values are
permitted.
|
Iterate
Logic
|
Set<Entry<K, V>> mapValues =
map.entrySet();
|
Complexity
|
Read/Search any element O(1)/Update : O(1)/Delete : O(1)/Add at
beginning: O(1)/Add in middle: O(n)/Add at end: O(n)
|
More
info
|
ü
This implementation differs
from HashMap in that it maintains a doubly-linked list running
through all of its entries. This linked list defines the iteration ordering,
which is normally the order in which keys were inserted into the map (insertion-order).
ü
Note that insertion order is not affected if a
key is re-inserted into the map. (A key k is
reinserted into a map m if m.put(k, v) is invoked when m.containsKey(k) would
return true immediately prior to the invocation.)
ü
This technique is particularly useful if a
module takes a map on input, copies it, and later returns results whose order
is determined by that of the copy. (Clients generally appreciate having
things returned in the same order they were presented.)
ü
A special constructor is provided to create a
linked hash map whose order of iteration is the order in which its entries
were last accessed, from least-recently accessed to most-recently (access-order)
ü
It maintains a doubly-linked list because with
an additional hash map, you can implement deletes in O(1). If you are using a
singly linked list, delete would take O(n).
ü
Consider a hash map for storing a key value
pair, and another internal hash map with keys pointing to nodes in the linked
list. When deleting, if it's a doubly linked list, I can easily get to the
previous element and make it point to the following element. This is not
possible with a singly linked list.
ü
Consider a hash map for storing a key value
pair, and another internal hash map with keys pointing to nodes in the linked
list. When deleting, if it's a doubly linked list, we can easily get to the
previous element and make it point to the following element. This is not possible
with a singly linked list.
ü
The putAll method is used to copy all of the
mappings from the specified map to this map.
Copies all of the mappings from the specified map to this
map (optional operation). The effect of this call is equivalent to that of calling
put(k, v) on this map once for each mapping from key k to value v in the
specified map. The behavior of this operation is undefined if the specified
map is modified while the operation is in progress.
`
ü
"one entry access for each mapping"
means the effect of putall call is equivalent to that of calling put(k, v) on
this map once for each mapping from key k to value v in the specified map.
ü
How it works internally?
Internally LinkedHashMap uses an Entry object called
header as a starting node to link with all the items that you add to the map.
So in this case it will be
The header Entry object is both the start and the end of
the doubly linked list since header.before = header.after = header when it
initially constructs.
[header] -> ["a"] -> ["b"] ->
["c"] -> ["d"] -> [header]
A zero size LinkedHashMap contains just the Head element with before
and after pointing to itself.
void init() {
header = new Entry<K,V>(-1, null,
null, null);
header.before = header.after = header;
}
Each node contains references to the
previous and to the next node . A new node is always added to the end of the
list. In order to do so, the last node's and the header node's links have to
be adjusted.
The new node's next reference will
point to the head.
The new node's previous reference will
point to the current last node.
The current last node's next reference
will point to the new node instead of head.
Head's previous reference will point
to the new node
private static class Entry<K,V> extends HashMap.Entry<K,V>
{
// These
fields comprise the doubly linked list used for iteration.
Entry<K,V> before, after;
Entry(int
hash, K key, V value, HashMap.Entry<K,V> next) {
super(hash, key, value, next);
}
An entry finds its location in the array based on its
hash value. If an array element is already occupied, the new entry replaces
the old entry and the old entry is linked to the new one.
|
22. Collection Name
|
java.util.Set
|
Implementation
Of
|
extends Collection<E>
|
Is
Ordered
|
No. Depends on subtypes.
|
Is Resizable
|
Yes
|
Is
Thread Safe
|
No. Depends on subtypes .
|
Duplicate
allowed
|
No
|
Null
allowed
|
At most one null element
|
Iterate
Logic
|
Iterator<E> iterator();
|
Complexity
|
Worst case O(n), best case O(1)
|
More
info
|
ü
A Set is a Collection that cannot contains
duplicate elements
ü
Method declared in set is almost similar to
Collection interface but they have different meaning, adds the restriction
that duplicate elements are prohibited and also helpful in creating more
specific java documentation.
ü
Two Set instances are equal if they contain
the same elements.
ü
Some set implementations have restrictions on
the elements that they may contain. For example, some implementations
prohibit null elements, and some have restrictions on the types of their
elements. Attempting to add an ineligible element throws an unchecked
exception, typically NullPointerException or ClassCastException.
ü
If you insert duplicate in Set it will replace
the older value.
|
23. Collection Name
|
java.util. AbstractSet
|
Implementation
Of
|
extends AbstractCollection<E>
implements Set<E>
|
Is
Ordered
|
No
|
Is
Resizable
|
Yes
|
Is
Thread Safe
|
No.
Depends on subtypes
|
Duplicate
allowed
|
No
|
Null
allowed
|
No
|
Iterate
Logic
|
Iterator<E>
iterator();
|
Complexity
|
NA
|
More
info
|
ü
Note that this class does not override any of
the implementations from the AbstractCollection class. It merely adds
implementations for equals and hashCode.
ü
Implements method like
·
removeAll()
·
hashCode()
·
equals(Object o)
ü
equals(Object o) Returns true if the given object is also a
set, the two sets have the same size, and every member of the given set is
contained in this set. This ensures that the equals method works properly
across different implementations of the Set interface.
This implementation first checks if the specified object
is this set; if so it returns true. Then, it checks if the specified object
is a set whose size is identical to the size of this set; if not, it returns
false. If so, it returns containsAll((Collection) o).
ü
hashCode() returns the hash code value for
this set. The hash code of a set is defined to be the sum of the hash codes
of the elements in the set, where the hash code of a null element is defined
to be zero. This ensures that s1.equals(s2) implies that
s1.hashCode()==s2.hashCode() for any two sets s1 and s2, as required by the
general contract of java.lang.Object.hashCode().
This implementation iterates over the set, calling the
hashCode method on each element in the set, and adding up the results.
|
Coming soon .. Things must know about java collection API - Part IV
No comments:
Post a Comment