Defining Maps, Sets, etc and then passing/getting them - java

I've read that when you define a {Map, Set, Etc} it is good practice use the interface name as so:
Map<Integer, String> map = new LinkedHashMap<Integer, String>();
instead of:
LinkedHashMap<Integer, String> map = new LinkedHashMap<Integer, String>();
I'm not sure why this is, but I've put it to practice in hopes I will understand at a later time. Maybe that time has come.
So I create a class that defines one and create a getter for the Map:
class Data{
private Map<Integer, String> map;
public Data(){
map = new LinkedHashMap<Integer, String>();
//dynamically put some things into the map
}
public Map<Integer, String> getMap(){
return map;
}
}
Now I come to my first impasse. I can't return a LinkedHashMap, I have to return a Map.
So in another class I get that Map
class Foo{
public Foo{
Data data = new Data();
Map<Integer, String> map = data.getMap();
}
}
Can someone explain what is happening to map when it gets passed?
Is it still a LinkedHashMap?
Is the data changed at all?
What would happen to the order of the Map if, after calling getData(), I put something in the Map?
Why wouldn't/shouldn't I just define the Map as in the second code snippet?
Is my method of getting the map done in ignorance?
Should I just make map public?

Now I come to my first impasse. I can't return a LinkedHashMap
Here's the misunderstanding: you can return a LinkedHashMap, because a LinkedHashMap is a Map, a particular sort of Map, but a Map anyway.
Can someone explain what is happening to map when it gets passed?
When it's passed, it is seen as any Map, like incognito, but it remains the same.
Is it still a LinkedHashMap?
Yes.
Is the data changed at all?
No.
What would happen to the order of the Map if, after calling getData(), I put something in the Map?
This is another topic.
Why wouldn't/shouldn't I just define the Map as in the second code snippet?
You needn't do that, since a LinkedHashMap is a Map (on the other hand, a Map is not necessarily a LinkedHashMap).
Is my method of getting the map done in ignorance?
Should I just make map public?
No.

You may want your variable to be able do what it needs to do and still be as flexible as possible in the way it does that. So your variable should be of the type that covers all your needed functionality but is as high as possible in hirachy.

Related

What is the difference between the following statements in terms of HashMap? [duplicate]

What is the difference between the following maps I create (in another question, people answered using them seemingly interchangeably and I'm wondering if/how they are different):
HashMap<String, Object> map = new HashMap<String, Object>();
Map<String, Object> map = new HashMap<String, Object>();
There is no difference between the objects; you have a HashMap<String, Object> in both cases. There is a difference in the interface you have to the object. In the first case, the interface is HashMap<String, Object>, whereas in the second it's Map<String, Object>. But the underlying object is the same.
The advantage to using Map<String, Object> is that you can change the underlying object to be a different kind of map without breaking your contract with any code that's using it. If you declare it as HashMap<String, Object>, you have to change your contract if you want to change the underlying implementation.
Example: Let's say I write this class:
class Foo {
private HashMap<String, Object> things;
private HashMap<String, Object> moreThings;
protected HashMap<String, Object> getThings() {
return this.things;
}
protected HashMap<String, Object> getMoreThings() {
return this.moreThings;
}
public Foo() {
this.things = new HashMap<String, Object>();
this.moreThings = new HashMap<String, Object>();
}
// ...more...
}
The class has a couple of internal maps of string->object which it shares (via accessor methods) with subclasses. Let's say I write it with HashMaps to start with because I think that's the appropriate structure to use when writing the class.
Later, Mary writes code subclassing it. She has something she needs to do with both things and moreThings, so naturally she puts that in a common method, and she uses the same type I used on getThings/getMoreThings when defining her method:
class SpecialFoo extends Foo {
private void doSomething(HashMap<String, Object> t) {
// ...
}
public void whatever() {
this.doSomething(this.getThings());
this.doSomething(this.getMoreThings());
}
// ...more...
}
Later, I decide that actually, it's better if I use TreeMap instead of HashMap in Foo. I update Foo, changing HashMap to TreeMap. Now, SpecialFoo doesn't compile anymore, because I've broken the contract: Foo used to say it provided HashMaps, but now it's providing TreeMaps instead. So we have to fix SpecialFoo now (and this kind of thing can ripple through a codebase).
Unless I had a really good reason for sharing that my implementation was using a HashMap (and that does happen), what I should have done was declare getThings and getMoreThings as just returning Map<String, Object> without being any more specific than that. In fact, barring a good reason to do something else, even within Foo I should probably declare things and moreThings as Map, not HashMap/TreeMap:
class Foo {
private Map<String, Object> things; // <== Changed
private Map<String, Object> moreThings; // <== Changed
protected Map<String, Object> getThings() { // <== Changed
return this.things;
}
protected Map<String, Object> getMoreThings() { // <== Changed
return this.moreThings;
}
public Foo() {
this.things = new HashMap<String, Object>();
this.moreThings = new HashMap<String, Object>();
}
// ...more...
}
Note how I'm now using Map<String, Object> everywhere I can, only being specific when I create the actual objects.
If I had done that, then Mary would have done this:
class SpecialFoo extends Foo {
private void doSomething(Map<String, Object> t) { // <== Changed
// ...
}
public void whatever() {
this.doSomething(this.getThings());
this.doSomething(this.getMoreThings());
}
}
...and changing Foo wouldn't have made SpecialFoo stop compiling.
Interfaces (and base classes) let us reveal only as much as is necessary, keeping our flexibility under the covers to make changes as appropriate. In general, we want to have our references be as basic as possible. If we don't need to know it's a HashMap, just call it a Map.
This isn't a blind rule, but in general, coding to the most general interface is going to be less brittle than coding to something more specific. If I'd remembered that, I wouldn't have created a Foo that set Mary up for failure with SpecialFoo. If Mary had remembered that, then even though I messed up Foo, she would have declared her private method with Map instead of HashMap and my changing Foo's contract wouldn't have impacted her code.
Sometimes you can't do that, sometimes you have to be specific. But unless you have a reason to be, err toward the least-specific interface.
Map is an interface that HashMap implements. The difference is that in the second implementation your reference to the HashMap will only allow the use of functions defined in the Map interface, while the first will allow the use of any public functions in HashMap (which includes the Map interface).
It will probably make more sense if you read Sun's interface tutorial
Map has the following implementations:
HashMap Map m = new HashMap();
LinkedHashMap Map m = new LinkedHashMap();
Tree Map Map m = new TreeMap();
WeakHashMap Map m = new WeakHashMap();
Suppose you have created one method (this is just pseudocode).
public void HashMap getMap(){
return map;
}
Suppose your project requirements change:
The method should return map contents - Need to return HashMap.
The method should return map key's in insertion order - Need to change return type HashMap to LinkedHashMap.
The method should return map key's in sorted order - Need to change return type LinkedHashMap to TreeMap.
If your method returns specific classes instead of something that implements the Map interface, you have to change the return type of getMap() method each time.
But if you use the polymorphism feature of Java, and instead of returning specific classes, use the interface Map, it improves code reusability and reduces the impact of requirement changes.
I was just going to do this as a comment on the accepted answer but it got too funky (I hate not having line breaks)
ah, so the difference is that in
general, Map has certain methods
associated with it. but there are
different ways or creating a map, such
as a HashMap, and these different ways
provide unique methods that not all
maps have.
Exactly--and you always want to use the most general interface you possibly can. Consider ArrayList vs LinkedList. Huge difference in how you use them, but if you use "List" you can switch between them readily.
In fact, you can replace the right-hand side of the initializer with a more dynamic statement. how about something like this:
List collection;
if(keepSorted)
collection=new LinkedList();
else
collection=new ArrayList();
This way if you are going to fill in the collection with an insertion sort, you would use a linked list (an insertion sort into an array list is criminal.) But if you don't need to keep it sorted and are just appending, you use an ArrayList (More efficient for other operations).
This is a pretty big stretch here because collections aren't the best example, but in OO design one of the most important concepts is using the interface facade to access different objects with the exact same code.
Edit responding to comment:
As for your map comment below, Yes using the "Map" interface restricts you to only those methods unless you cast the collection back from Map to HashMap (which COMPLETELY defeats the purpose).
Often what you will do is create an object and fill it in using it's specific type (HashMap), in some kind of "create" or "initialize" method, but that method will return a "Map" that doesn't need to be manipulated as a HashMap any more.
If you ever have to cast by the way, you are probably using the wrong interface or your code isn't structured well enough. Note that it is acceptable to have one section of your code treat it as a "HashMap" while the other treats it as a "Map", but this should flow "down". so that you are never casting.
Also notice the semi-neat aspect of roles indicated by interfaces. A LinkedList makes a good stack or queue, an ArrayList makes a good stack but a horrific queue (again, a remove would cause a shift of the entire list) so LinkedList implements the Queue interface, ArrayList does not.
As noted by TJ Crowder and Adamski, one reference is to an interface, the other to a specific implementation of the interface. According to Joshua Block, you should always attempt to code to interfaces, to allow you to better handle changes to underlying implementation - i.e. if HashMap suddenly was not ideal for your solution and you needed to change the map implementation, you could still use the Map interface, and change the instantiation type.
Map is the static type of map, while HashMap is the dynamic type of map. This means that the compiler will treat your map object as being one of type Map, even though at runtime, it may point to any subtype of it.
This practice of programming against interfaces instead of implementations has the added benefit of remaining flexible: You can for instance replace the dynamic type of map at runtime, as long as it is a subtype of Map (e.g. LinkedHashMap), and change the map's behavior on the fly.
A good rule of thumb is to remain as abstract as possible on the API level: If for instance a method you are programming must work on maps, then it's sufficient to declare a parameter as Map instead of the stricter (because less abstract) HashMap type. That way, the consumer of your API can be flexible about what kind of Map implementation they want to pass to your method.
In your second example the "map" reference is of type Map, which is an interface implemented by HashMap (and other types of Map). This interface is a contract saying that the object maps keys to values and supports various operations (e.g. put, get). It says nothing about the implementation of the Map (in this case a HashMap).
The second approach is generally preferred as you typically wouldn't want to expose the specific map implementation to methods using the Map or via an API definition.
Adding to the top voted answer and many ones above stressing the "more generic, better", I would like to dig a little bit more.
Map is the structure contract while HashMap is an implementation providing its own methods to deal with different real problems: how to calculate index, what is the capacity and how to increment it, how to insert, how to keep the index unique, etc.
Let's look into the source code:
In Map we have the method of containsKey(Object key):
boolean containsKey(Object key);
JavaDoc:
boolean java.util.Map.containsValue(Object value)
Returns true if this map maps one or more keys to the specified value. More formally, returns true if and only if this map contains at least one mapping to a value v such that (value==null ? v==null : value.equals(v)). This operation will probably require time linear in the map size for most implementations of the Map interface.
Parameters:value
value whose presence in this map is to betested
Returns:true
if this map maps one or more keys to the specified
valueThrows:
ClassCastException - if the value is of an inappropriate type for this map (optional)
NullPointerException - if the specified value is null and this map does not permit null values (optional)
It requires its implementations to implement it, but the "how to" is at its freedom, only to ensure it returns correct.
In HashMap:
public boolean containsKey(Object key) {
return getNode(hash(key), key) != null;
}
It turns out that HashMap uses hashcode to test if this map contains the key. So it has the benefit of hash algorithm.
You create the same maps.
But you can fill the difference when you will use it. With first case you'll be able to use special HashMap methods (but I don't remember anyone realy useful), and you'll be able to pass it as a HashMap parameter:
public void foo (HashMap<String, Object) { ... }
...
HashMap<String, Object> m1 = ...;
Map<String, Object> m2 = ...;
foo (m1);
foo ((HashMap<String, Object>)m2);
Map is interface and Hashmap is a class that implements Map Interface
Map is the Interface and Hashmap is the class that implements that.
So in this implementation you create the same objects
HashMap is an implementation of Map so it's quite the same but has "clone()" method as i see in reference guide))
HashMap<String, Object> map1 = new HashMap<String, Object>();
Map<String, Object> map2 = new HashMap<String, Object>();
First of all Map is an interface it has different implementation like - HashMap, TreeHashMap, LinkedHashMap etc. Interface works like a super class for the implementing class. So according to OOP's rule any concrete class that implements Map is a Map also. That means we can assign/put any HashMap type variable to a Map type variable without any type of casting.
In this case we can assign map1 to map2 without any casting or any losing of data -
map2 = map1

Adding a value to a hashmap java

Sorry, new to Java, probably a really simple question.
Let's say I have an outter map, that has a (key, inner map), and in the inner map I have (String, Double).
So it looks something like this.
HashMap<String, Double> inner = new HashMap<String, Double>();
HashMap<Integer, Map<String, Double>> outter = new HashMap<Integer, Map<String, Double>>();
inner.put("MyVal", 24.5930553450692151964475150);
inner.put("MyVal2", 48.6514790522118734018261775);
outter.put(20151205, inner)
I end up with and outter map like this:
{20151205={MyVal=24.593055345069214, MyVal2=48.651479052211876}}
Now let's say I no longer have access to the inner map, so I can't put any more values in it. But, I want to add a MyVal3 using only the outter map.
How can this be done?
I want to end up with something like this using code for only the outter map.
{20151205={MyVal=24.593055345069214, MyVal2=48.651479052211876, MyVal3=48.4846855555555}}
Thanks a lot! Couldn't find exactly this question elsewhere on SO.
As always thanks everyone!
You always have access to the inner map, but you need to get the key.
Then you simply put.
outter.get(20151205).put("MyVal3", 48.4846855555) ;
Beware of the Nullpointerexception when you try to get a key that doesn't exist

Creating a map of maps from a map Java 8

I have a Map<String, List<SomeClassA>> that I'm trying to convert into a Map<String, Map<String, List<SomeWrapperOfClassA>>> and I'm just having so much trouble wrapping my head around how to do this.
Really, all the information needed to create the map should be in the objects of type SomeClassA - say
SomeClassA:
String attributeA;
String attributeB;
SomeClassB someOtherInfo;
SomeClassB:
String attribute C;
And I want to say it's a map based on this:
Map<attributeA's values,Map<attribute C vals, List SomeWrapperOfClassA>>
where the list is only of SomeWrapperClassA that has those values of attributeA and attributeB. I was thinking it might have to do with groupingBy, but I'm not too familiar with how to do it in such a way that its nested like this.
(or for the sake of simplicity, any help just getting the original list of SomeClassA into a Map<String, Map<String, List<SomeClassA>>> would already be a huge help.
I haven't quite gotten the hang of Java 8 and the more complex streaming concepts yet, so some help would be greatly appreciated. I'm only familiar with the basics.
I am not sure what you meant by:
Map<String, Map<String, List<SomeClassA>>>, what is the key here to group by? in general if you want to group List<SomeClassA> by say attributeA from SomeClassA you can do this:
List<SomeClassA>.stream().collect(Collectors.groupingBy(someClsA-> someClsA.getAttributeA()));
If I understand your questions correctly I would express it as follows:
Given:
class ClassA {
public String getA();
public ClassB getB();
}
class ClassB {
public String getC();
}
Map<String, List<ClassA>> input;
How would I create a Map<String, Map<String, List<ClassB>> where the key of the inner map is the result of getA?
If that's correct then you aren't looking to change the keys of the outer map at all. That makes it a good candidate for Map.replaceAll. For clarity I've split the collector into a separate method so it's clear what's happening:
input.replaceAll(listA.stream().collect(mapCollector()));
private Collector<A, ?, Map<String, List<B>> mapCollector() {
return Collectors.groupingBy(ClassA::getA,
Collectors.mapping(ClassA::getB,
Collectors.toList()));
}
Explaining the method it says group As by getA as key, then collect those As by mapping using getB then putting in a list.
If you particularly want a new map (rather than changing the original one) then:
Map<String, Map<String, List<ClassB>>> output = input.entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().stream().collect(mapCollector()));
It’s not entirely clear what you want to achieve. Apparently, the keys of your source map are irrelevant and you only want to process the SomeClassA instances contained in the value lists. So, the first step is to stream over the map’s values, i.e. sourceMap.values().stream(), then flatten this Stream<List<SomeClassA>> to a Stream<SomeClassA> via flatMap(List::stream).
Grouping these SomeClassA instances by one of their properties works indeed straight-forwardly via groupingBy, which needs another nested groupingBy to group each group further by “Attribute C”:
Map<String, Map<String, List<SomeClassA>>> resultMap
= sourceMap.values().stream().flatMap(List::stream)
.collect(Collectors.groupingBy(SomeClassA::getAttributeA,
Collectors.groupingBy(a->a.getSomeOtherInfo().getAttributeC())));
To convert the SomeClassA instances to SomeWrapperClassA instances, we need another nested collector for the innermost groupingBy; the mapping collector allows to map the values before transferring to another collector, which has to be the toList() collector, which was formerly implicit.
Now, it might be better to start using import static java.util.stream.Collectors.*;
Map<String, Map<String, List<SomeWrapperClassA>>> resultMap
= sourceMap.values().stream().flatMap(List::stream)
.collect(groupingBy(SomeClassA::getAttributeA, groupingBy(
a -> a.getSomeOtherInfo().getAttributeC(),
mapping(a->new SomeWrapperClassA(a.getAttributeA(),a.getAttributeB()), toList()))));

Loading map with keys that are not present, else load default

Here is an example method:
public void loadStuff(Map<String, Object> someMap) {
Map<String, Object> myMap = new HashMap<String, Object>();
//I now load defaults here first
myMap.put("One", someObject);
myMap.put("two", someObject);
myMap.put("three", someObject);
//Now I put the entire someMap so that only those keys that are present in someMap are overridden in myMap and others remain default.
myMap.putAll(someMap);
}
Now, is there a better way of doing these redundant puts as the number of defaults in my scenario are a lot.
Consider creating an initial map with your defaults in, and then use:
// Alternatively, you could use clone()
Map<String, Object> myMap = new HashMap<String, Object>(defaults);
myMap.putAll(someMap);
Aside from anything else that means you can load the "default map" from a properties file or whatever.
If you really don't like the fact that it will put each value twice, you could write a loop to check for each key - but I'd personally just use the above code. It's simple and it should work fine.
Are you wanting to preload a single answer for just a few items, or are you wanting a default for all unfound keys? If you want to change the default answer from null to something else, see this question. If you're wanting to preload some items, then you'll need to put all of them, though it's best not to embed the values in code like that; use a for loop instead that iterates over a single official list of the keys.
If you are going to be initializing blank copies of this Map frequently, it will make more sense to have a template Map that each myMap is constructed from; either a HashMap wrapped as unmodifiable or a Guava ImmutableMap are good choices there. Constructing from a preexisting Map instead of copying all of the elements into the new HashMap is much more efficient since the new one knows how big to make itself.

What is the difference between the HashMap and Map objects in Java?

What is the difference between the following maps I create (in another question, people answered using them seemingly interchangeably and I'm wondering if/how they are different):
HashMap<String, Object> map = new HashMap<String, Object>();
Map<String, Object> map = new HashMap<String, Object>();
There is no difference between the objects; you have a HashMap<String, Object> in both cases. There is a difference in the interface you have to the object. In the first case, the interface is HashMap<String, Object>, whereas in the second it's Map<String, Object>. But the underlying object is the same.
The advantage to using Map<String, Object> is that you can change the underlying object to be a different kind of map without breaking your contract with any code that's using it. If you declare it as HashMap<String, Object>, you have to change your contract if you want to change the underlying implementation.
Example: Let's say I write this class:
class Foo {
private HashMap<String, Object> things;
private HashMap<String, Object> moreThings;
protected HashMap<String, Object> getThings() {
return this.things;
}
protected HashMap<String, Object> getMoreThings() {
return this.moreThings;
}
public Foo() {
this.things = new HashMap<String, Object>();
this.moreThings = new HashMap<String, Object>();
}
// ...more...
}
The class has a couple of internal maps of string->object which it shares (via accessor methods) with subclasses. Let's say I write it with HashMaps to start with because I think that's the appropriate structure to use when writing the class.
Later, Mary writes code subclassing it. She has something she needs to do with both things and moreThings, so naturally she puts that in a common method, and she uses the same type I used on getThings/getMoreThings when defining her method:
class SpecialFoo extends Foo {
private void doSomething(HashMap<String, Object> t) {
// ...
}
public void whatever() {
this.doSomething(this.getThings());
this.doSomething(this.getMoreThings());
}
// ...more...
}
Later, I decide that actually, it's better if I use TreeMap instead of HashMap in Foo. I update Foo, changing HashMap to TreeMap. Now, SpecialFoo doesn't compile anymore, because I've broken the contract: Foo used to say it provided HashMaps, but now it's providing TreeMaps instead. So we have to fix SpecialFoo now (and this kind of thing can ripple through a codebase).
Unless I had a really good reason for sharing that my implementation was using a HashMap (and that does happen), what I should have done was declare getThings and getMoreThings as just returning Map<String, Object> without being any more specific than that. In fact, barring a good reason to do something else, even within Foo I should probably declare things and moreThings as Map, not HashMap/TreeMap:
class Foo {
private Map<String, Object> things; // <== Changed
private Map<String, Object> moreThings; // <== Changed
protected Map<String, Object> getThings() { // <== Changed
return this.things;
}
protected Map<String, Object> getMoreThings() { // <== Changed
return this.moreThings;
}
public Foo() {
this.things = new HashMap<String, Object>();
this.moreThings = new HashMap<String, Object>();
}
// ...more...
}
Note how I'm now using Map<String, Object> everywhere I can, only being specific when I create the actual objects.
If I had done that, then Mary would have done this:
class SpecialFoo extends Foo {
private void doSomething(Map<String, Object> t) { // <== Changed
// ...
}
public void whatever() {
this.doSomething(this.getThings());
this.doSomething(this.getMoreThings());
}
}
...and changing Foo wouldn't have made SpecialFoo stop compiling.
Interfaces (and base classes) let us reveal only as much as is necessary, keeping our flexibility under the covers to make changes as appropriate. In general, we want to have our references be as basic as possible. If we don't need to know it's a HashMap, just call it a Map.
This isn't a blind rule, but in general, coding to the most general interface is going to be less brittle than coding to something more specific. If I'd remembered that, I wouldn't have created a Foo that set Mary up for failure with SpecialFoo. If Mary had remembered that, then even though I messed up Foo, she would have declared her private method with Map instead of HashMap and my changing Foo's contract wouldn't have impacted her code.
Sometimes you can't do that, sometimes you have to be specific. But unless you have a reason to be, err toward the least-specific interface.
Map is an interface that HashMap implements. The difference is that in the second implementation your reference to the HashMap will only allow the use of functions defined in the Map interface, while the first will allow the use of any public functions in HashMap (which includes the Map interface).
It will probably make more sense if you read Sun's interface tutorial
Map has the following implementations:
HashMap Map m = new HashMap();
LinkedHashMap Map m = new LinkedHashMap();
Tree Map Map m = new TreeMap();
WeakHashMap Map m = new WeakHashMap();
Suppose you have created one method (this is just pseudocode).
public void HashMap getMap(){
return map;
}
Suppose your project requirements change:
The method should return map contents - Need to return HashMap.
The method should return map key's in insertion order - Need to change return type HashMap to LinkedHashMap.
The method should return map key's in sorted order - Need to change return type LinkedHashMap to TreeMap.
If your method returns specific classes instead of something that implements the Map interface, you have to change the return type of getMap() method each time.
But if you use the polymorphism feature of Java, and instead of returning specific classes, use the interface Map, it improves code reusability and reduces the impact of requirement changes.
I was just going to do this as a comment on the accepted answer but it got too funky (I hate not having line breaks)
ah, so the difference is that in
general, Map has certain methods
associated with it. but there are
different ways or creating a map, such
as a HashMap, and these different ways
provide unique methods that not all
maps have.
Exactly--and you always want to use the most general interface you possibly can. Consider ArrayList vs LinkedList. Huge difference in how you use them, but if you use "List" you can switch between them readily.
In fact, you can replace the right-hand side of the initializer with a more dynamic statement. how about something like this:
List collection;
if(keepSorted)
collection=new LinkedList();
else
collection=new ArrayList();
This way if you are going to fill in the collection with an insertion sort, you would use a linked list (an insertion sort into an array list is criminal.) But if you don't need to keep it sorted and are just appending, you use an ArrayList (More efficient for other operations).
This is a pretty big stretch here because collections aren't the best example, but in OO design one of the most important concepts is using the interface facade to access different objects with the exact same code.
Edit responding to comment:
As for your map comment below, Yes using the "Map" interface restricts you to only those methods unless you cast the collection back from Map to HashMap (which COMPLETELY defeats the purpose).
Often what you will do is create an object and fill it in using it's specific type (HashMap), in some kind of "create" or "initialize" method, but that method will return a "Map" that doesn't need to be manipulated as a HashMap any more.
If you ever have to cast by the way, you are probably using the wrong interface or your code isn't structured well enough. Note that it is acceptable to have one section of your code treat it as a "HashMap" while the other treats it as a "Map", but this should flow "down". so that you are never casting.
Also notice the semi-neat aspect of roles indicated by interfaces. A LinkedList makes a good stack or queue, an ArrayList makes a good stack but a horrific queue (again, a remove would cause a shift of the entire list) so LinkedList implements the Queue interface, ArrayList does not.
As noted by TJ Crowder and Adamski, one reference is to an interface, the other to a specific implementation of the interface. According to Joshua Block, you should always attempt to code to interfaces, to allow you to better handle changes to underlying implementation - i.e. if HashMap suddenly was not ideal for your solution and you needed to change the map implementation, you could still use the Map interface, and change the instantiation type.
Map is the static type of map, while HashMap is the dynamic type of map. This means that the compiler will treat your map object as being one of type Map, even though at runtime, it may point to any subtype of it.
This practice of programming against interfaces instead of implementations has the added benefit of remaining flexible: You can for instance replace the dynamic type of map at runtime, as long as it is a subtype of Map (e.g. LinkedHashMap), and change the map's behavior on the fly.
A good rule of thumb is to remain as abstract as possible on the API level: If for instance a method you are programming must work on maps, then it's sufficient to declare a parameter as Map instead of the stricter (because less abstract) HashMap type. That way, the consumer of your API can be flexible about what kind of Map implementation they want to pass to your method.
In your second example the "map" reference is of type Map, which is an interface implemented by HashMap (and other types of Map). This interface is a contract saying that the object maps keys to values and supports various operations (e.g. put, get). It says nothing about the implementation of the Map (in this case a HashMap).
The second approach is generally preferred as you typically wouldn't want to expose the specific map implementation to methods using the Map or via an API definition.
Adding to the top voted answer and many ones above stressing the "more generic, better", I would like to dig a little bit more.
Map is the structure contract while HashMap is an implementation providing its own methods to deal with different real problems: how to calculate index, what is the capacity and how to increment it, how to insert, how to keep the index unique, etc.
Let's look into the source code:
In Map we have the method of containsKey(Object key):
boolean containsKey(Object key);
JavaDoc:
boolean java.util.Map.containsValue(Object value)
Returns true if this map maps one or more keys to the specified value. More formally, returns true if and only if this map contains at least one mapping to a value v such that (value==null ? v==null : value.equals(v)). This operation will probably require time linear in the map size for most implementations of the Map interface.
Parameters:value
value whose presence in this map is to betested
Returns:true
if this map maps one or more keys to the specified
valueThrows:
ClassCastException - if the value is of an inappropriate type for this map (optional)
NullPointerException - if the specified value is null and this map does not permit null values (optional)
It requires its implementations to implement it, but the "how to" is at its freedom, only to ensure it returns correct.
In HashMap:
public boolean containsKey(Object key) {
return getNode(hash(key), key) != null;
}
It turns out that HashMap uses hashcode to test if this map contains the key. So it has the benefit of hash algorithm.
You create the same maps.
But you can fill the difference when you will use it. With first case you'll be able to use special HashMap methods (but I don't remember anyone realy useful), and you'll be able to pass it as a HashMap parameter:
public void foo (HashMap<String, Object) { ... }
...
HashMap<String, Object> m1 = ...;
Map<String, Object> m2 = ...;
foo (m1);
foo ((HashMap<String, Object>)m2);
Map is interface and Hashmap is a class that implements Map Interface
Map is the Interface and Hashmap is the class that implements that.
So in this implementation you create the same objects
HashMap is an implementation of Map so it's quite the same but has "clone()" method as i see in reference guide))
HashMap<String, Object> map1 = new HashMap<String, Object>();
Map<String, Object> map2 = new HashMap<String, Object>();
First of all Map is an interface it has different implementation like - HashMap, TreeHashMap, LinkedHashMap etc. Interface works like a super class for the implementing class. So according to OOP's rule any concrete class that implements Map is a Map also. That means we can assign/put any HashMap type variable to a Map type variable without any type of casting.
In this case we can assign map1 to map2 without any casting or any losing of data -
map2 = map1

Categories