I answered a question regaurding an ImmutableMap. I suggested using the Proxy pattern.
The problem with this is that Map contains a put method, which would throw an UnsupportedOperationException. Replacing other instances of Map with ImmutableMap would break the Liskov Subsitution principle. Not only that, the need to declare put and putAll [violates the interface segregation principle]
Technically, there is no way to replace a Map instance with ImmutableMap, since Map is simply an interface. So my question is:
Would creating an ImmutableMap using the Map interface be considered breaking the LSP, since Map contains a put and putAll method? Would not implementing Map be considered an "Alternative Classes with Different Interfaces" code smell? How would one create an ImmutableMap that abides by the LSP yet doesn't contain code smells?
In my view, an ImmutableMap should implement Map. It would be a bad idea not to implement Map as there are many methods that accept a Map as an argument and only use it in a read-only sense. I don't believe this does violate the Liskov Subsitution principle because the contract for Map makes it clear that put is an optional operation.
It is not ideal that classes implementing Map have to implement put, but the alternative would have been to have a complex hierarchy of interfaces each only including a subset of the possible optional methods. If there are n optional methods, there would have to be 2^n interfaces to cover all the combinations. I don't know the value of n, but there are some non-obvious optional operations, such as whether or not the Iterator returned by map.entrySet().iterator() supports the setValue operation. If you combined this hierarchy with the hierarchy of interfaces and abstract classes that actually exists already (including AbstractMap, SortedMap, NavigableMap, ConcurrentMap, ConcurrentNavigableMap...) you would have a total mess.
So there is no perfect answer to this, but in my view the best solution is to make ImmutableMap implement Map and ensure that every method you write with a Map as an argument clearly documents any properties the Map must have and the exceptions thrown if the wrong type of Map is passed.
I don't understand this code Map<E, Integer> d = new HashTable<E, Integer>(list.size()); : we create a new object but is it a map or a hashtable? what is the difference between the both of them? I thought that a map is just a way to put 2 element together like a key and its value (for exemple {3; Detroit})
is it a map or a hashtable?
Yes.
The static, compile time type of the reference is Map. As others have already pointed out, it's an interface. You can call all the methods on the Map interface and know that they'll obey the contract and behave as describe.
The dynamic, run time type of the object reference refers to is Hashtable. It implements all the methods in the Map interface in its own way.
The key idea is that the compile time type of a reference is separate from the run time type of the object on the heap that it points to.
Hashtable is a JDK 1.0 class that sticks around for compatibility reasons. It's been retrofitted to implement the Map interface, which was introduced later. You'd be well advised to choose another implementation, such as HashMap, depending on your requirements.
The last part of Hashtable contains the reason why it should not be used:
As of the Java 2 platform v1.2, this class was retrofitted to implement the Map interface, making it a member of the Java Collections Framework. Unlike the new collection implementations, Hashtable is synchronized. If a thread-safe implementation is not needed, it is recommended to use HashMap in place of Hashtable. If a thread-safe highly-concurrent implementation is desired, then it is recommended to use ConcurrentHashMap in place of Hashtable.
This means that it is less efficient than HashMap for single-thread models and less efficient than ConcurrentHashMap for multi-threaded models.
Understanding how compile and run time types differ is crucial to understanding how object oriented polymorphism works. This is true for all OO languages: C++, Java, .NET, Python, etc.
Map is an interface. Hashtable is one of the classes that implements the Map interface.
See the Java Doc for the Map interface. Specifically the section that says all known implementing classes.
Any class that implements a Map provides a key->value data-structure. A Map being an interface defines the contract that all implementing classes must adhere to. By itself, a Map cannot be instantiated.
Note that while Hashtable should ideally have been named as HashTable following the java naming conventions, this is is a pre-historic class in Java which exists even before the standard java naming conventions came into existence. Therefore, it is still called Hashtable and not HashTable as wrongly mentioned in your question.
Map is an interface. HashTable is one implementation of that interface. There are several others, such as HashMap, SortedMap, etc. The interface defines the programming API; the implementation defines how that API is implemented. Different implementations may have different runtime performance characteristics.
With regard to interfaces vs. implementations, you may find my answer to Java - HashMap vs Map objects here helpful.
I'm a bit confused about the advice to use the Interface for a Java class, like in this thread: Why should the interface for a Java class be preferred?
I understand why you would want to use the interface: if something changes later you have less code to clean up.
But aren't there cases in which using the Interface would prevent you from being able to take advantage of the performance reason why you chose that particular class in the first place?
For instance, if I have a TreeMap, I assume that I should be able to locate any element in at most O(logn). That's why it has nice methods I can take advantage of like higherEntry(), lowerEntry(), lastEntry().
If I instead reference this TreeMap as a Map, now I believe I am forced to iterate one element at a time through my list in O(n) to locate that entry.
I'm new to Java, so let me know if I'm missing something here.
If I instead reference this TreeMap as a Map, now I believe I am
forced to iterate one element at a time through my list in O(n) to
locate that entry.
No you are not forced to do that. If you are sure that your Map reference is holding a reference to TreeMap, and you want to access specific method of TreeMap, then you can always typecast the Map reference to a TreeMap reference, and then access the appropriate method, like, higherEntry(), lowerEntry().
But, the only caveat is that, you have to be sure that your Map reference is actually pointing to a TreeMap, to avoid getting a ClassCastException at runtime.
This is implied by the fact that, a super class and it's sub classes are covariant in nature. So, you can perform cast between them, provided you are not breaking the rules at runtime (That is having the super class reference holding the reference to some other sub class instance, which is not covariant with the sub class you are casting to).
Now for your example, since the TreeMap also implements the NavigableMap interface, which is a sub interface of Map interface, so you can use it instead of Map interface. So, you can have the advantage of polymorphism, without the need to typecast.
If you want to use methods like higherEntry, lowerEntry, and lastEntry, then just use the NavigableMap interface instead of the Map interface or the TreeMap class.
In general, use interfaces as often as possible, and use the most general interface you can that supports all the operations you'd want to use.
I recently ran across a set of code which instantiated local maps as following:
HashMap<String, Object> theMap = new HashMap<String, Object>();
Typically, when I've seen HashMaps used (and used them myself), the local variables are simply Map (the interface), rather than being tied to the specific implementation. Obviously this is required if the Map could potentially be instantiated as various Map types (e.g. accepting a parameter). However, in the case of something like the above where it's defined and instantiated at the same point, is there an underlying reason to only use the interface type, or is it simply style/convention?
(I originally misunderstood the question based on the title, but I've included both type and variable conventions as both are interesting.)
What's important is that it's a map: something you look things up in. The rest is an implementation detail.
I would suggest giving it a semantic name, e.g.
Map<String, Object> nameToSessionMap = ...
... that way when you read the code, you'll know what the keys and values are meant to be.
As for the type of the variable - again, I'd typically use the interface rather than the implementation partly because it indicates I'm not using any members which are specific to the type. I don't want to emphasize the implementation in the code, usually... it means when I do care about the implementation, I can make that more obvious.
Declaring the object as a Map will allow the compiler to protect you from calling methods which are specific to HashMap. This will allow you to substitute another Map implementation in the future without worrying about having method calls which do not exist in the Map interface.
In general people use mostly Map to make the least amount of assumptions on the implementation.
It cannot be that the Classname is used for the additional methods as only clone() is added by HashMap, which has fallen in disuse (for good reasons).
What could be is that the map needs to be Serializable for one reason or another, and the plain Map interface does not extend it, but HashMap does implement it.
Even in this case, it keeps it generic. Coding to interface ensures you are using a Map and not a specific implementation of it.
I was surprised by the fact that Map<?,?> is not a Collection<?>.
I thought it'd make a LOT of sense if it was declared as such:
public interface Map<K,V> extends Collection<Map.Entry<K,V>>
After all, a Map<K,V> is a collection of Map.Entry<K,V>, isn't it?
So is there a good reason why it's not implemented as such?
Thanks to Cletus for a most authoritative answer, but I'm still wondering why, if you can already view a Map<K,V> as Set<Map.Entries<K,V>> (via entrySet()), it doesn't just extend that interface instead.
If a Map is a Collection, what are the elements? The only reasonable answer is "Key-value pairs"
Exactly, interface Map<K,V> extends Set<Map.Entry<K,V>> would be great!
but this provides a very limited (and not particularly useful) Map abstraction.
But if that's the case then why is entrySet specified by the interface? It must be useful somehow (and I think it's easy to argue for that position!).
You can't ask what value a given key maps to, nor can you delete the entry for a given key without knowing what value it maps to.
I'm not saying that that's all there is to it to Map! It can and should keep all the other methods (except entrySet, which is redundant now)!
From the Java Collections API Design FAQ:
Why doesn't Map extend Collection?
This was by design. We feel that
mappings are not collections and
collections are not mappings. Thus, it
makes little sense for Map to extend
the Collection interface (or vice
versa).
If a Map is a Collection, what are the
elements? The only reasonable answer
is "Key-value pairs", but this
provides a very limited (and not
particularly useful) Map abstraction.
You can't ask what value a given key
maps to, nor can you delete the entry
for a given key without knowing what
value it maps to.
Collection could be made to extend
Map, but this raises the question:
what are the keys? There's no really
satisfactory answer, and forcing one
leads to an unnatural interface.
Maps can be viewed as Collections (of
keys, values, or pairs), and this fact
is reflected in the three "Collection
view operations" on Maps (keySet,
entrySet, and values). While it is, in
principle, possible to view a List as
a Map mapping indices to elements,
this has the nasty property that
deleting an element from the List
changes the Key associated with every
element before the deleted element.
That's why we don't have a map view
operation on Lists.
Update: I think the quote answers most of the questions. It's worth stressing the part about a collection of entries not being a particularly useful abstraction. For example:
Set<Map.Entry<String,String>>
would allow:
set.add(entry("hello", "world"));
set.add(entry("hello", "world 2"));
(assuming an entry() method that creates a Map.Entry instance)
Maps require unique keys so this would violate this. Or if you impose unique keys on a Set of entries, it's not really a Set in the general sense. It's a Set with further restrictions.
Arguably you could say the equals()/hashCode() relationship for Map.Entry was purely on the key but even that has issues. More importantly, does it really add any value? You may find this abstraction breaks down once you start looking at the corner cases.
It's worth noting that the HashSet is actually implemented as a HashMap, not the other way around. This is purely an implementation detail but is interesting nonetheless.
The main reason for entrySet() to exist is to simplify traversal so you don't have to traverse the keys and then do a lookup of the key. Don't take it as prima facie evidence that a Map should be a Set of entries (imho).
While you've gotten a number of answers that cover your question fairly directly, I think it might be useful to step back a bit, and look at the question a bit more generally. That is, not to look specifically at how the Java library happens to be written, and look at why it's written that way.
The problem here is that inheritance only models one type of commonality. If you pick out two things that both seem "collection-like", you can probably pick out a 8 or 10 things they have in common. If you pick out a different pair of "collection-like" things, they'll also 8 or 10 things in common -- but they won't be the same 8 or 10 things as the first pair.
If you look at a dozen or so different "collection-like" things, virtually every one of them will probably have something like 8 or 10 characteristics in common with at least one other one -- but if you look at what's shared across every one of them, you're left with practically nothing.
This is a situation that inheritance (especially single inheritance) just doesn't model well. There's no clean dividing line between which of those are really collections and which aren't -- but if you want to define a meaningful Collection class, you're stuck with leaving some of them out. If you leave only a few of them out, your Collection class will only be able to provide quite a sparse interface. If you leave more out, you'll be able to give it a richer interface.
Some also take the option of basically saying: "this type of collection supports operation X, but you're not allowed to use it, by deriving from a base class that defines X, but attempting to use the derived class' X fails (e.g., by throwing an exception).
That still leaves one problem: almost regardless of which you leave out and which you put in, you're going to have to draw a hard line between what classes are in and what are out. No matter where you draw that line, you're going to be left with a clear, rather artificial, division between some things that are quite similar.
I guess the why is subjective.
In C#, I think Dictionary extends or at least implements a collection:
public class Dictionary<TKey, TValue> : IDictionary<TKey, TValue>,
ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>,
IDictionary, ICollection, IEnumerable, ISerializable, IDeserializationCallback
In Pharo Smalltak as well:
Collection subclass: #Set
Set subclass: #Dictionary
But there is an asymmetry with some methods. For instance, collect: will takes association (the equivalent of an entry), while do: take the values. They provide another method keysAndValuesDo: to iterate the dictionary by entry. Add: takes an association, but remove: has been "suppressed":
remove: anObject
self shouldNotImplement
So it's definitively doable, but leads to some other issues regarding the class hierarchy.
What is better is subjective.
The answer of cletus is good, but I want to add a semantic approach. To combine both makes no sense, think of the case you add a key-value-pair via the collection interface and the key already exists. The Map-interface allows only one value associated with the key. But if you automatically remove the existing entry with the same key, the collection has after the add the same size as before - very unexpected for a collection.
Java collections are broken. There is a missing interface, that of Relation. Hence, Map extends Relation extends Set. Relations (also called multi-maps) have unique name-value pairs. Maps (aka "Functions"), have unique names (or keys) which of course map to values. Sequences extend Maps (where each key is an integer > 0). Bags (or multi-sets) extend Maps (where each key is an element and each value is the number of times the element appears in the bag).
This structure would allow intersection, union etc. of a range of "collections". Hence, the hierarchy should be:
Set
|
Relation
|
Map
/ \
Bag Sequence
Sun/Oracle/Java ppl - please get it right next time. Thanks.
Map<K,V> should not extend Set<Map.Entry<K,V>> since:
You can't add different Map.Entrys with the same key to the same Map, but
You can add different Map.Entrys with the same key to the same Set<Map.Entry>.
If you look at the respective data structure you can easily guess why Map is not a part of Collection. Each Collection stores a single value where as a Map stores key-value pair. So methods in Collection interface are incompatible for Map interface. For example in Collection we have add(Object o). What would be such implementation in Map. It doesn't make sense to have such a method in Map. Instead we have a put(key,value) method in Map.
Same argument goes for addAll(), remove(), and removeAll() methods. So the main reason is the difference in the way data is stored in Map and Collection.
Also if you recall Collection interface implemented Iterable interface i.e. any interface with .iterator() method should return an iterator which must allow us to iterate over the values stored in the Collection. Now what would such method return for a Map? Key iterator or a Value iterator? This does not make sense either.
There are ways in which we can iterate over keys and values stores in a Map and that is how it is a part of Collection framework.
Exactly, interface Map<K,V> extends
Set<Map.Entry<K,V>> would be great!
Actually, if it were implements Map<K,V>, Set<Map.Entry<K,V>>, then I tend to agree.. It seems even natural. But that doesn't work very well, right? Let's say we have HashMap implements Map<K,V>, Set<Map.Entry<K,V>, LinkedHashMap implements Map<K,V>, Set<Map.Entry<K,V> etc... that is all good, but if you had entrySet(), nobody will forget to implement that method, and you can be sure that you can get entrySet for any Map, whereas you aren't if you are hoping that the implementor has implemented both interfaces...
The reason I don't want to have interface Map<K,V> extends Set<Map.Entry<K,V>> is simply, because there will be more methods. And after all, they are different things, right? Also very practically, if I hit map. in IDE, I don't want to see .remove(Object obj), and .remove(Map.Entry<K,V> entry) because I can't do hit ctrl+space, r, return and be done with it.
Straight and simple.
Collection is an interface which is expecting only one Object, whereas Map requires Two.
Collection(Object o);
Map<Object,Object>