why people use "Map m= new HashMap()" or "List l = new ArrayList()"?

W

www

Hi,

I saw in many places that people use:

Map m= new HashMap();

or

List l = new ArrayList();

I *rarely* see people do:

HashMap m= new HashMap();

or

ArrayList l = new ArrayList();

Is any specific reason for such a practice?

I noticed Map does not have clone(), but HashMap does.
 
R

Richard Reynolds

www said:
Hi,

I saw in many places that people use:

Map m= new HashMap();

or

List l = new ArrayList();

I *rarely* see people do:

HashMap m= new HashMap();

or

ArrayList l = new ArrayList();

Is any specific reason for such a practice?

I noticed Map does not have clone(), but HashMap does.

They're using the most "general" type that they can to give them the
greatest flexibility in their design. It's a trait of OO programming in
general. Try reading some basic OO design tutorials, in particulay you might
want to pay attention to generalisation, specialisation and, in Java for
instance, the use of abstract classes and interfaces.
 
M

Mark Space

www said:
I saw in many places that people use:

Map m= new HashMap();
I *rarely* see people do:

HashMap m= new HashMap();

1. Convention. As you say, many people do it this way.

2. Flexibility. It may be easier to change the implementation of the
former than the latter. The latter form would encourage other
programmers to code to the specific HashMap() interface, rather than the
more general Map() interface. With Map(), you can just plug in a new
type of map like

Map m = new LinkedHashMap();

But if you've coded to a specific type of Hash Map this change may be
not so easy to make.

3. Probably some other reasons I can't think of right now... always it
depends on your application.
 
L

Lew

Mark said:
1. Convention. As you say, many people do it this way.

2. Flexibility. It may be easier to change the implementation of the
former than the latter. The latter form would encourage other
programmers to code to the specific HashMap() interface, rather than the
more general Map() interface. With Map(), you can just plug in a new
type of map like

Map m = new LinkedHashMap();

But if you've coded to a specific type of Hash Map this change may be
not so easy to make.

3. Probably some other reasons I can't think of right now... always it
depends on your application.

It is a best practice to prefer the most general type possible for the
compile-time type of a variable. This provides the most bug-free and
maintainable code.

The word is "prefer", not "demand", and "possible for the ... type", which
might be a specific implementation but usually isn't.

Consider the fairly common error of using Vector for a List when you don't
need its special features. If you declared

List <String> stuff = new Vector <String> ();

then it's much easier to change to

List <String> stuff = new ArrayList <String> ();

and later, if you see that you need specific performance characteristics,

List <String> stuff = new TreeList <String> ();

or even

List <String> stuff
= Collections.synchronizedList( new ArrayList <String> () );

No other code will depend on non-List methods such as those of Vector, so you
are much safer in making the changes.

Read Joshua Bloch's excellent book /Effective Java/ for details on this and
many other best practices.
 
J

Jim Korman

Hi,

I saw in many places that people use:

Map m= new HashMap();

or

List l = new ArrayList();

I *rarely* see people do:

HashMap m= new HashMap();

or

ArrayList l = new ArrayList();

Is any specific reason for such a practice?

I noticed Map does not have clone(), but HashMap does.

The rule I use is if the collection I'm using is local to a method,
or totally private to a class, then I'll use the specific collection
type. If the collection is visible anywhere outside the class or
especially subclasses, I use the collection interfaces.

Jim
 
L

Lew

Jim said:
The rule I use is if the collection I'm using is local to a method,
or totally private to a class, then I'll use the specific collection
type. If the collection is visible anywhere outside the class or
especially subclasses, I use the collection interfaces.

I use "declare the most general type" even for private items. Of course,
"most general" might mean a specific implementation if the algorithm demands it.
 
K

Knute Johnson

Lew said:
It is a best practice to prefer the most general type possible for the
compile-time type of a variable. This provides the most bug-free and
maintainable code.

The word is "prefer", not "demand", and "possible for the ... type",
which might be a specific implementation but usually isn't.

Consider the fairly common error of using Vector for a List when you
don't need its special features. If you declared

List <String> stuff = new Vector <String> ();

then it's much easier to change to

List <String> stuff = new ArrayList <String> ();

and later, if you see that you need specific performance characteristics,

List <String> stuff = new TreeList <String> ();

or even

List <String> stuff
= Collections.synchronizedList( new ArrayList <String> () );

No other code will depend on non-List methods such as those of Vector,
so you are much safer in making the changes.

Read Joshua Bloch's excellent book /Effective Java/ for details on this
and many other best practices.

It doesn't make a lot of sense to me. Generics were added to closely
control the type of parameters passed to a class that we then want to
make less type specific? It makes no sense to turn a LinkedList for
example into a plain List as you lose all of what makes it a LinkedList.
Of course you could assign it to a Deque.

knute...
 
L

Lew

Knute said:
It doesn't make a lot of sense to me. Generics were added to closely
control the type of parameters passed to a class that we then want to
make less type specific? It makes no sense to turn a LinkedList for
example into a plain List as you lose all of what makes it a LinkedList.
Of course you could assign it to a Deque.

Well, duhy, if you need the specific type you use the specific type. No one
is saying to be stupid about it.
 
W

Wayne

www said:
Hi,

I saw in many places that people use:
Map m= new HashMap();
or
List l = new ArrayList();
I *rarely* see people do:
HashMap m= new HashMap();
or
ArrayList l = new ArrayList();
Is any specific reason for such a practice?

You bet. When the map is visible outside of the
current method (or class), you only want external
code to know that you have a Map. They should not
care about the *implementation* of that Map, which
the implementer can then change without potentially
harming users of that code.

This is a standard practice called "data hiding"
or other more impressive terms.

Note: when you (someday) learn about "generics",
don't fall into the trap of:
List l = new ArrayList<String>();
Instead use:
List<String> l = new ArrayList<String>();

Verbally you would say that "l is a list of Strings".

-Wayne
 
C

Chris ( Val )

You bet. When the map is visible outside of the
current method (or class), you only want external
code to know that you have a Map.
From what I have read, I don't think that is quite
the reson behind it.
They should not
care about the *implementation* of that Map, which
the implementer can then change without potentially
harming users of that code.

Yes, however; that is typical of an interface hiding
its implementation, via a layer of abstraction.
This is a standard practice called "data hiding"
or other more impressive terms.

But "data hiding" is an artifact of encapsulation,
generally achieved through the implementation of
private accessors - This answers a different question
to what the OP really asked.
From what I understand, the OP wants to know why
one construct "Map m= new HashMap();" is prefered
over another "HashMap m= new HashMap();".

[snip]

In my studies so far (and I have not seen anyone mention
this yet), but the following constructs:

"Map m= new HashMap();" or...
"public void someFunc( Map m ); // Accepts HashMap, etc.

....appear to be what is known as: "Programming To An Interface".

It is said to be preferred and encouraged because it offers the
most flexible solution of all.

Cheers,

Chris
 
R

Roedy Green

Map m= new HashMap();

The main reason is to avoid the temptation to use methods of HashMap
that are not part of Map. That way you can change to some other sort
of Map very easily. If you allowed yourself to use methods peculiar
to HashMap, you would have to rewrite the code to avoid them when you
wanted to change the Map implementation.

From a raw speed point of view, the Map idiom is not a good idea since
method calls via an interface reference are slower than calls via a
class reference.

You might say, but I will NEVER want to change the Map implementation.
None of the others are even remotely close to what I need. Consider
what happened when Sun introduced StringBuilder to replace
StringBuffer. StringBuilder did not exist at the time many people
wrote their code. Similarly HashMap largely replaced HashTable, and
ArrayList replaced Vector. What you are doing is making it easier to
plug in some new improved implementation in future that you have never
heard of now.
 
K

Knute Johnson

Lew said:
Well, duhy, if you need the specific type you use the specific type. No
one is saying to be stupid about it.

The only two classes extended from List that you would ever want to do
this with are ArrayList and Vector. Since everyone hates Vector,
explain to me in what actual case this would be of any benefit and not
just confusing.

knute...
 
P

Patricia Shanahan

Knute said:
The only two classes extended from List that you would ever want to do
this with are ArrayList and Vector. Since everyone hates Vector,
explain to me in what actual case this would be of any benefit and not
just confusing.

knute...

You might choose LinkedList because you need e.g. a Queue. On the other
hand, it is also reasonable to choose LinkedList because you need a List
and preliminary estimates suggest that non-tail insertions and removals
will dominate over indexed access.

I would use List, except for the actual constructor call, in the second
case.

Patricia
 
D

Daniel Dyer

From a raw speed point of view, the Map idiom is not a good idea since
method calls via an interface reference are slower than calls via a
class reference.

I doubt you'd ever notice the difference. Let the JIT take care of
optimising this rather than doing it explicitly.

Dan.
 
L

Lew

Patricia said:
You might choose LinkedList because you need e.g. a Queue. On the other
hand, it is also reasonable to choose LinkedList because you need a List
and preliminary estimates suggest that non-tail insertions and removals
will dominate over indexed access.

I would use List, except for the actual constructor call, in the second
case.

I simply point to the body of literature, such as Joshua Bloch's /Effective
Java/, that make the case for this practice. They provide much better
arguments than I will here in favor of it. That's where I learned it -
reading the experts. Instead of challenging me to justify the practice, write
to them.
 
L

Lew

Daniel said:
I doubt you'd ever notice the difference. Let the JIT take care of
optimising this rather than doing it explicitly.

I was at a meeting for software developers the other night. The guest speaker
spoke of his decades' work in software development, pointing out that *every*
time he profiled a bit of code the bottleneck was *never* where he predicted.

He used the absolutes. Every time he looked, the bottleneck was never where
he thought. Only by actual measurement did he find the slowdown. He says,
every time.

Based on the rest of his presentation, he was knowledgeable and proficient in
software development. I find his claim credible.
 
R

Robert Klemme

From a raw speed point of view, the Map idiom is not a good idea since
method calls via an interface reference are slower than calls via a
class reference.

Um, where do you take that from? I cannot remember having heard that
claim before and off the top of my head I could not imagine a cause for
this. Can you elaborate or show some evidence? Thank you!

Kind regards

robert
 
Z

Zig

Um, where do you take that from? I cannot remember having heard that
claim before and off the top of my head I could not imagine a cause for
this. Can you elaborate or show some evidence? Thank you!

When you call a method on an interface type, the compiler will end up
emitting an

invokeinterface

call. Whereas, calling the same method on a non-final class method will
result in a

invokevirtual

In an invokevirtual, the runtime can simply jump strait to the class
method table and lookup the correct address for the method, and jump into
it. In an invokeinterface, the runtime has to determine which class method
corresponds to the interface method, thus invokeinterface is slower than
invokevirtual.

That said, it's a detail. You should assume that 99% of your cpu time is
spent inside the method itself, not by the runtime looking for which
method to invoke, unless your method is just { }.

Also, if you were to write your code as:

final Map m=new HashMap()

I assume that a smart compiler will infer the correct type, recognize
there is no need for virtual method invocation, and use direct method
invocation, thus providing better performance than either approach.

But, the real only place to care is in big number crunching algorithms,
where you expect to invoke methods trillions of times per calculation.

HTH,

-Zig
 
L

Lew

Zig said:
But, the real only place to care is in big number crunching algorithms,
where you expect to invoke methods trillions of times per calculation.

At that point, measurement (with -server on the JVM) will tell you if the
optimizer is smart enough to deal with this for you.

As usual, "loosest appropriate type" hinges on the definition of "appropriate".
 
Z

Zig

Hi,

I saw in many places that people use:

Map m= new HashMap();

The best reason I can offer here is that this should tell a maintence
programmer:

* The HashMap implementation is not strictly required
* Defer to documentation for implicit assumptions required of the
implementation

Eg, if you were to instead say

import java.util.concurrent.*;

ConcurrentMap m=new ConcurrentHashMap()

This tells the user that the choice of a Hash'ed map is not strictly
required, but the map must be safe for access by other threads. It also
implies that callers should be safe to iterate through m.entrySet(), but
those methods should beware that the iterator could return entries that
did not exist when the iterator was created, or might not return entries
that did exist when the iterator was created.

Likewise, using

SortedMap m=new TreeMap()

tells the reader that your algorithm implicitly requires that entries be
sorted, and may fail spuriously if the implementation changes.

In the end,

Map m=new HashMap()

This says that, in the future, this algorithm will still work correctly if
the keys are converted to Enums and the map is replaced with the faster
EnumMap implementation as

Map m=new EnumMap(MyEnum.class);

However, the same programmer should really read the documentation and
scratch their head before attempting to refit this code with
Collections.synchronizedMap, Collections.unmodifiableMap, an
implementation of ConcurrentMap, etc.

HTH,

-Zig
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top