I have come across a piece of code where I found
public class MapImpl {
private static MapImpl mpl = new MapImpl();
Map<String,String> hm;
private MapImpl() {
hm = new HashMap<>();
}
public addContentsToMap(Map<String,String> m){
this.hm=m;
}
public Map returnMap(){
new HashMap<>(hm);
}
}
I like to know here that when the default constructor is called the map is initialized to hashmap, and when addContentsToMap is called a map is formed with values.
I see that the returnMap uses the constructor of the HashMap(Map m). I have gone through the source code of HashMap but was clueless.
It takes any implementation of Map interface and constructs a HashMap which also is an implementation of Map interface.
Developers like Hash-Collections (HashSet, HashMap etc.) including HashMap because they provide expected O(1) get and contains time.
It can be useful, once you have a Map which isn't a HashMap (e.g. Properties) and you know that it'll be large and you will read from it many times, it's useful to switch to a different implementation of a Map.
Documentation:
public HashMap(Map<? extends K,? extends V> m)
Constructs a new HashMap with the same mappings as the specified Map. The HashMap is created with default load factor (0.75) and an initial capacity sufficient to hold the mappings in the specified Map.
Parameters:
m - the map whose mappings are to be placed in this map
Throws:
NullPointerException - if the specified map is null
Related
The internal implementation of HashSet
.......................................
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
{
private transient HashMap<E,Object> map;
private static final Object PRESENT = new Object();
//constructors
public HashSet() {
map = new HashMap<>();
}
public HashSet(int initialCapacity) {
map = new HashMap<>(initialCapacity);
}
public HashSet(int initialCapacity, float loadFactor) {
map = new HashMap<>(initialCapacity, loadFactor);
}
public HashSet(Collection<? usnoextends E> c) {
map = new HashMap<>(Math.imax((int) (c.size()/.75f) + 1, 16));
addAll(c);
}
//add method
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
}
Internally HashSet is using HashMap only and performance-wise HashMap is faster than HashSet
So why we are not using HashMap directly instead of going for HashSet.
Because HashSet is another type of collection - focused on the single object rather than pair of items. To make HashMap work like HashSet we would need to provide everywhere some artificial value object like
HashMap<MyItem, Object> set;
and then instead of e.g. set.add(new MyItem()) use something like set.put(new MyItem(), null) what makes no sense and can cause serious issues (when type of Object will be changed, when you will need to serialize etc)
Moreover internal implementation is nothing you should take care of - it can change in the next Java version (probably won't) and some another mechanism will be used underneath. The most important is Set interface and the fact HashSet is implementing this
What is the difference between Lists, ArrayLists, Maps, Hashmaps, Collections etc..?
As pointed by #m.antkowicz, though it internally uses HashMap, there is no guarantee.
Another major reason:
Generally in large projects, interfaces are defined independent of implementations.
If a business interface expects Set (or even Collection), it will define it as Set(or Collection)
The interface does not care about the underlying implementations(they assume the expected behavior will be maintained)
Any business concrete implementation of the interface should declare the method signature exactly(to override)
So, they also will use Set(or Collection)
Also, different implementations of Set use different Map
ConcurrentSkipListSet uses ConcurrentNavigableMap
HashSet uses HashMap
So, this is difficult to use exactly in interface contracts.
I was wondering how could i link my XSSFSheet by a string? I need a variable similar to Map, but it should return XSSFSheet, not object.
Something like this:
List<XSSFSheet, String> list = new ArrayList<XSSFSheet, String>
list.add(mySheet1, "ID154");
list.add(mySheet2, "ID4564");
list.get("ID4564"); //Gets mySheet1 by that ID
The easiest way to do so is a Map, but it would be a (very common) misuse of this datastructure. The correct way would be to create a simple dataholder class containing your two strings and have a List of objects of these datatypes.
On the other hand, reading your question again... a Map might not be so wrong at all in this case asy you have key-value-pairs.
So Map<String, XSSFSheet> map = new HashMap<>() should be what you're looking for.
No it is not. A list is an object for storing a collection of objects that are of the same type.to store key value pairs like what you want to do you'd need to use a HashMap object which is designed to store key, value pairs.
HashMaps come in the form HashMap<key, value> with key being the type for the key, and value being the type for the corresponding value.
Your code would then look like this:
HashMap<String, XSSFSheet> list = new HashMap<String, XSSFSheet>();
list.put("ID154", mySheet1);
list.put("ID4564", mySheet2);
list.get("ID4564"); //Gets mySheet1 by that ID
For more information read this page.
I don't think there is any structural overhead in using Map in your case.
Complexity of accessing an entry in a HashMap is O(m), where m is the number of elements in the longest linked list associated with an entry in a HashMap.
But if you are very much specific in not using Map, then you can make use of the KeyValue Tuple from the JavaTuples library.
A KeyValue is a Tuple from JavaTuples library that deals with only 2 elements – a key and a value.
Since this KeyValue is a generic class, it can hold any type of value in it.
Since KeyValue is a Tuple, hence it also has all the characterstics of JavaTuples:
They are Typesafe
They are Immutable
They are Iterable
They are Serializable
They are Comparable (implements Comparable)
They implement equals() and hashCode()
They also implement toString()
Class Declaration
public final class KeyValue<A, B> extends Tuple
implements IValueKey<A>, IValueValue<B>
Class hierarchy
Object ↳ org.javatuples.Tuple
↳ org.javatuples.KeyValue
So in your case you can use something like this.
Change according to your use case.
package com.test.UnitTests;
import java.util.*;
import org.javatuples.KeyValue;
class KeyValueTest {
public static void main(String[] args) {
KeyValue<Integer, String> kv1 = KeyValue.with(Integer.valueOf(1), "Maths");
KeyValue<Integer, String> kv2 = KeyValue.with(Integer.valueOf(2), "English");
List<KeyValue> testKVs = new ArrayList<KeyValue>();
testKVs.add(kv1);
testKVs.add(kv2);
//assuming that you want to fetch the value for key = 2
int key = 2;
String value = fetchValue(key,testKVs);
if(value!=null) {
System.out.println("Value for Key: "+key +" = "+value);
}else {
System.out.println("No Key-Value pair found with Key:"+key);
}
}
private static String fetchValue(int i, List<KeyValue> testKVs) {
for (KeyValue testKv : testKVs) {
if ((int) testKv.getKey() == i) {
return (String)testKv.getValue();
}
}
return null;
}
}
To learn about javatuples more, use this link:
https://www.geeksforgeeks.org/keyvalue-class-in-java-tuples/
You can download the jar at:
http://www.java2s.com/Code/Jar/j/Downloadjavatuples10jar.htm
I have a map like this with several million entries:
private final Map<String, SomeItem> tops = new HashMap<>();
I need to get list of values, which could be done by calling java.util.Map values() method.
Is Collection of values created every time I call values() method or is it pre-computed from performance perspective?
As my Map has several millions elements, I do not want to create new list object every time values() is called.
Below is the copied implementation of Map.values() in java.util.HashMap:
public Collection<V> values() {
Collection<V> vs = values;
if (vs == null) {
vs = new Values();
values = vs;
}
return vs;
}
This clearly shows that the value collection isn't created unless necessary. So, there should not be additional overhead caused by calls to values()
One important point here may be: It does not matter!
But first, referring to the other answers so far: The collection that is returned there is usually "cached", in that it is lazily created, and afterwards, the same instance will be returned. For example, considering the implementation in the HashMap class:
public Collection<V> values() {
Collection<V> vs;
return (vs = values) == null ? (values = new Values()) : vs;
}
This is even specified (as part of the contract, as an implementation specification) in the documentation of the AbstractMap class (which most Map implementations are based on) :
The collection is created the first time this method is called, and returned in response to all subsequent calls. No synchronization is performed, so there is a slight chance that multiple calls to this method will not all return the same collection.
But now, one could argue that the implementation might change later. The implementation of the HashMap class could change, or one might switch to another Map implementation that does not extend AbstractMap, and which is implemented differently. The fact that it is currently implemented like this is (for itself) no guarantee that it will always be implemented like this.
So the more important point (and the reason why it does not matter) is that the values() method is indeed supposed to return a collection view. As stated in the documentation of the Map interface :
The Map interface provides three collection views, which allow a map's contents to be viewed as a set of keys, collection of values, or set of key-value mappings.
and specifically, the documentation of the Map#values() method :
Returns a Collection view of the values contained in this map. The collection is backed by the map, so changes to the map are reflected in the collection, and vice-versa.
I cannot imagine a reasonable way of implementing such a view that involves processing all values of the Map.
So for example, imagine the implementation in HashMap was like this:
public Collection<V> values() {
return new Values();
}
Then it would return a new collection each time that it was called. But creating this collection does not involve processing the values at all.
Or to put it that way: The cost of calling this method is independent of the size of the map. It basically has the cost of a single object creation, regardless of whether the map contains 10 or 10000 elements.
As others have mentioned you can see this by looking at the code. You can also code up a quick example to prove it to yourself. The code below will print true 10 times as the object identity will always be the same for values.
public static void main(String[] args) {
Map<String, String> myMap = new HashMap();
Collection<String> lastValues = myMap.values();
for (int i=0; i < 10; i++) {
System.out.println(lastValues == myMap.values());
lastValues = myMap.values();
}
}
The following code will print true the first time and then false the next 9 times.
public static void main(String[] args) {
Map<String, String> myMap = new HashMap();
Collection<String> lastValues = myMap.values();
for (int i=0; i < 10; i++) {
System.out.println(lastValues == myMap.values());
lastValues = myMap.values();
myMap = new HashMap();
}
}
One more suggestion after reading this thread, if the Map tops declared contents are not changed - you could use google guava ImmutableMap object. For more info- UnmodifiableMap (Java Collections) vs ImmutableMap (Google)
I am making a class that maps Strings to Integers. I want to be able to get the Integer associated with a particular String and iterate through the entries, which are defined as another class that implements Map.Entry<String, Integer>.
Currently I have this:
public class MyMap implements Iterable<MyEntry> {
private final Map<String, Integer> wrappedMap =
new HashMap<String, Integer>();
#Override
public Iterator<MyEntry> iterator() {
return wrappedMap.entrySet().iterator();
}
//more methods
}
It's not compiling because of a type mismatch even though MyEntry implements Map.Entry<String, Integer>.
Is there a way to make a custom implementation of Map.Entry? Is there an easier way to do this that I'm overlooking? Thanks in advanced!
It's not compiling because MyEntry is not a part of the hashmap at all. If you want to return a list of MyEntry then you need to copy the data elements into a MyEntry instance and load that into a collection. Which is going to be slow and consume a considerable amount of memory.
It should be:
#Override
public Iterator<Map.Entry<String,Integer>> iterator() {
return wrappedMap.entrySet().iterator();
}
The call to entrySet() returns a Set which contains the mappings in the hashmap. So the iterator needs to iterate over Entry objects
Why not use just a regular map?
Map<String, MyEntry> map = new HashMap<String, MyEntry>();
Then you iterator will be simply this:
Iterator<MyEntry> iter = map.values().iterator();
Even though MyEntry implements Map.Entry<K,V>, it is not the case that an Iterator<MyEntry> implements Iterator<Map.Entry<K,V>>. For a class like Iterator, that distinction doesn't make intuitive sense to a human being, so let's instead think of a Box<E> class, which has .put(E) and .contains(E) methods. Is a Box<Dinosaur> a subclass of Box<Animal>? You might think so, but that's not the case: in a Box<Animal> it's legal to call .put(someMammal), but in a Box<Dinosaur> that is clearly illegal. Since Box<Dinosaur> can't support all actions that are legal on a Box<Animal>, it is definitely not a subclass and cannot be substituted in at will.
From the compiler's point of view, the same concern might apply to iterators, and so you can't overload .iterator() to return an object which is not an instance of Iterator<K,V>.
This is more a curiosity question than anything. Say I supply a LinkedHashMap with access ordering set to true to Collections.unmodifiableMap(). Since reads are actually modifying the map. Does it mean there are cases where the view returned by unmodifiableMap() is actually modifiable?
public class MyApp {
/**
* #param args
*/
public static void main(String[] args) {
Map<String, String> m = new LinkedHashMap<String,
String>(16,.75f,true);
Collections.unmodifiableMap(m);
}
}
The Map is modifying itself. Collections.unmodifiableMap() only provides a decorator for the Map which disallows modifications, it does not make the Map itself unmodifiable.
Collections.unmodifiableMap returns a new Map that throws exceptions when you try to modify it, using the existing Map that you passed in as a backing collection. It doesn't change the semantics of the existing Map.