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

R

Roedy Green

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.

how does that help reduce bugs? I would expect the opposite, to a
mild degree since it is less clear what classes you are actually
using.

You could for example use a LinkedList inadvertently and have it not
as obvious.
 
R

Roedy Green

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

What evidence do you have that it is possible to optimise away the
extra overhead of interface references? When you think about what has
to happen under the hood it would be quite a feat.

See the Goldfish book:

The Java Virtual Machine
ISBN10: 1-56592-194-1
Joshua Engel
http://www.amazon.com/gp/product/15...mp=1789&creative=9325&creativeASIN=1565921941

I have heard that the JVMs have been gradually improving the
implementation of interface references, however if I were given some
code to optimise for speed, one thing I would try would be to convert
interface to class references where possible at least for leaf calls
where the CPU spends most of its time.

There is no virtue in deliberately choosing a slower solution unless
there is some compensating benefit.

There is a sentiment you hear from people who have read Knuth but who
are not of his generation, reminiscent of the conspicuous consumption
of movie stars that there is some virtue in deliberately wasting
resources.

What Knuth was talking about was making code unreadable with peephole
optimisations better done by the compiler. I don't think that many
Java programmers are old enough to have ever even seen the kind of
ghastly code he was talking about. He did not intend for you to close
your eyes to speed considerations or deliberately choose the slowest
implementation on your first cut. You might as well write fast code
first time out if it is readable and easy to write.

Knuth would unlikely bawl you out for choosing the best algorithm
first time out. That's where you get your massive speed improvements
for the least amount of work.
 
L

Lew

Roedy said:
how does that help reduce bugs? I would expect the opposite, to a
mild degree since it is less clear what classes you are actually
using.

You could for example use a LinkedList inadvertently and have it not
as obvious.

Actually, for reasons that you stated,
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.

and others that Zig stated.

Joshua Bloch covers it quite well in /Effective Java/.
 
L

Lew

Roedy said:
What evidence do you have that it is possible to optimise away the
extra overhead of interface references? When you think about what has
to happen under the hood it would be quite a feat.

What evidence do you have that it won't?

The problem with optimization discussions is that, by all experienced
accounts, only actual measurement of a specific application's performance will
effect an accurate assessment of what to optimize for a given program on a
given JVM.

I have seen measured jumps of 50% in performance just by switching to a
"-server" JVM configuration for the exact same applications. Some JVMs do
escape analysis and massive inlining /at runtime/ of heavily-run segments of
code. Published benchmarks show a block of code speeding up as the optimizer
"settles in" to the usage pattern.

You cite Knuth as if choice of an interface variable over a class variable
were always an algorithmic decision, whereas in many cases the choice of, say,
a List implementation is irrelevant to the particular algorithm. Knuth warned
against the effects of premature optimization, which by all accounts is
defined as prior to measurement of the actual performance.

Naturally if the overhead of interface calls over class calls is an important
factor, then it makes sense to narrow the type of the relevant variables.
 
M

Michael Jung

Lew said:
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.

The people around my place who are responsible for tuning performance never
predict (except the obvious), they measure and then analyse. The thing is
that premature optimization does more harm than good. Almost every time.

Michael
 
W

www

Thank you all for all your responses.

However, I still didn't get the answer. My old code is like:

public class MyClass {
private Map<String, String> _map;

public MyClass() {
_map = new HashMap<String, String>();
}

public Map getMap() {
return _map.clone(); //Oops! wrong! no clone() method for Map
}
}

Now, my new code is like:

public class MyClass {
private HashMap<String, String> _map;

public MyClass() {
_map = new HashMap<String, String>();
}

public HashMap getMap() {
return ((HashMap)_map.clone()); //clone() is available for HashMap
}
}

Do you see anything wrong with my new code? Should I keep the old code
and re-write getMap() like:

public Map getMap() {
Map<String, String> tempMap = new HashMap<String, String>();
//then copy everyting from _map into tempMap

return tempMap;
}

Thank you very much.
 
P

Patricia Shanahan

www wrote:
....
public Map getMap() {
Map<String, String> tempMap = new HashMap<String, String>();
//then copy everyting from _map into tempMap

return tempMap;
}

public Map<String,String> getMap(){
return new HashMap<String,String>(_map);
}

Alternatively, if callers just need a view of _map without being able to
modify it, and should see changes to _map:

public Map<String,String> getMap(){
return Collections.unmodifiableMap(_map);
}

Patricia
 
L

Lew

www said:
However, I still didn't get the answer. My old code is like:

You did get the answer to the question that you asked, many times over.
public class MyClass {
private Map<String, String> _map;

By convention, variable names should not include underscores unless they
represent compile-time constants.
public MyClass() {
_map = new HashMap<String, String>();
}

public Map getMap() {
return _map.clone(); //Oops! wrong! no clone() method for Map
}
}

Now, my new code is like:

public class MyClass {
private HashMap<String, String> _map;

public MyClass() {
_map = new HashMap<String, String>();
}

public HashMap getMap() {

You can still return a type Map, and you must not omit the generic declaration.
return ((HashMap)_map.clone()); //clone() is available for
HashMap

But you are applying the cast to the result of clone(), not the variable
'_map' here.

Also, in Java casting and generics don't mix well.
}
}

Do you see anything wrong with my new code?

Yes.

How about this (which I've compiled, but not run)?

public class MapCloner
{
private Map <String, String> stuff = new HashMap <String, String> ();

/** Get the <code>stuff</code> map.
* @return <code>Map &lt; String, String &gt;</code> stuff.
*/
public Map <String, String> getStuff()
{
return new HashMap <String, String> ( stuff );
}

// TODO methods to put values into the Map, etc., go here

/** Main method.
* @param args <code>String []</code> program arguments.
*/
public static void main( String [] args)
{
// TODO code application logic here
}
}

Like clone(), the HashMap(Map<? extends K,? extends V> m) constructor does a
shallow copy.
 
W

www

Patricia said:
www wrote:
...

public Map<String,String> getMap(){
return new HashMap<String,String>(_map);
}

Alternatively, if callers just need a view of _map without being able to
modify it, and should see changes to _map:

public Map<String,String> getMap(){
return Collections.unmodifiableMap(_map);
}

Patricia

Thank you very much. That is great!
 
E

Eric Sosman

Knute Johnson wrote On 10/20/07 04:37,:
The only two classes extended from List that you would ever want to do
this with are ArrayList and Vector.

The documentation describes ten core classes that
implement List, of which eight are concrete classes.
Since everyone hates Vector,
explain to me in what actual case this would be of any benefit and not
just confusing.

Do you think your program is in its final form when
you have finished debugging it? Nobody, not even you,
will ever want to modify it? Nobody, not even you, will
ever want to change his mind about an implementation
choice? "Hmm: Profiling tells me that a lot of time is
spent expanding and re-expanding and re-re-expanding this
ArrayList. We don't seem to need random access; maybe
LinkedList would be better." This sort of thing never
happens to you?

If not, all I can say is that you are more gifted at
predicting the future than I am. Given my temporally
foreshortened foresight, I prefer to leave myself as many
chances to change my mind as I possibly can. YMMV.

... but when Java 9 brings us SuperList ("faster than
a speeding bullet"), I bet I'll have an easier time adapting
my code to use it than you will with yours.
 
A

Adam Maass

www said:
Thank you all for all your responses.

However, I still didn't get the answer. My old code is like:

public class MyClass {
private Map<String, String> _map;

public MyClass() {
_map = new HashMap<String, String>();
}

public Map getMap() {
return _map.clone(); //Oops! wrong! no clone() method for Map
}
}

Now, my new code is like:

public class MyClass {
private HashMap<String, String> _map;

public MyClass() {
_map = new HashMap<String, String>();
}

public HashMap getMap() {
return ((HashMap)_map.clone()); //clone() is available for HashMap
}
}

Do you see anything wrong with my new code? Should I keep the old code and
re-write getMap() like:

public Map getMap() {
Map<String, String> tempMap = new HashMap<String, String>();
//then copy everyting from _map into tempMap

There is a copy constructor on HashMap, so the copy is very straightforward
to make:

Map<String, String> tempMap = new HashMap<String, String>(_map);



Additionally, this may be an instance of needing to return a Map such that
the caller can't modify the internal state of the this object. For this,
there is:

Collections.unmodifiableMap(_map)


-- Adam Maass
 

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

Forum statistics

Threads
473,780
Messages
2,569,608
Members
45,253
Latest member
BlytheFant

Latest Threads

Top