- Feature Articles
- CodeSOD
- Error'd
- Forums
-
Other Articles
- Random Article
- Other Series
- Alex's Soapbox
- Announcements
- Best of…
- Best of Email
- Best of the Sidebar
- Bring Your Own Code
- Coded Smorgasbord
- Mandatory Fun Day
- Off Topic
- Representative Line
- News Roundup
- Editor's Soapbox
- Software on the Rocks
- Souvenir Potpourri
- Sponsor Post
- Tales from the Interview
- The Daily WTF: Live
- Virtudyne
Admin
I'm sorry, but that's just snobbery. First off, "better" is far too relative to have any real, broad meaning. Second, in your perfect world we'd only have a couple of languages.
I think it's worth noting that you mentioned Smalltalk, which borrowed very heavily from Simula, which in turn was just a superset of Algol. I guess Smalltalk wasn't much "better" than Simula, so we shouldn't have that one either.
Every commonly used language has borrowed from previous languages. Few have been revolutionary. When you really break it down, probably none of them should be viewed as revolutionary based purely on the differences between them and their predecessors. It's all about incremental changes. Incremental changes make massive differences (and hopefully improvements) over time.
Admin
Don't worry, they'll run out of TLNs after a while, and it'll probably stop growing. Only 800+
some odd days to go...
Admin
Admin
Admin
What they did has nothing to do with J2EE. "enterprise", I don't know, but it surely isn't J2EE.
Admin
Seeing as you cannot instaniate functionality, only implementation, and that's what is being done, it's a non-sequitur.
No, that's no true in the least, if we're generalizing. We may care about specific details, including performance. Other methods may not, and they should take a map.
However, it's irrelevant anyway.
You do no such thing. What flexibility have you lost? Make up a case.
You force one anyway, when you say: "= new HashMap()".
No, that's not apparent in the least.
It obviously does not because it cannot, it's impossible by the language design and it most certainly fucking isn't. It's just retarded OO wankery. It doesn't gain you anyway.
Then why must I say, "= new HashMap()". Obviously, this interface-only world you live in never actually constructs any objects.
Hilarious you would introduce another non-sequitur. Threading has nothing to do with the slowness of polymorphism.
Admin
That's what everyone on the "OO" camp is missing, you can't remove the implementation here. You must instaniate an implementation. You have no choice.
This is totally and completely seperate from what a method should take as arguments, or return.
If you can't understand that, you need to go back and work on programming fundamentals.
Admin
This is a real issue in .NET for example, where the collection interfaces are woefully inadequate and shouldn't even exist.
Admin
But you took your chance and used it twice!
Admin
There is exactly one method in HashMap that is not part of the Map interface: clone(). And you can get that functionality by using copy constructors rather than forcing clients to use HashMap.
Admin
Perhaps we better wonder why managers do this, my guess is the manager that decides to do this knows the 'Enterprise' guys and is paid by them, meaning corruption is the name of the game [:@]. These kind of things occur all too often. If the goal of any enterprise is to maximize their profit, how can any enterprise otherwise decide to change a working system into a less working, but 'enterprise' system; I bet if you ask any of these managers what they actual mean with 'make it more Enterprise' they can't come up with any descent explanation.
Admin
Okay I am going to dive into this.
first to reframe the question:
why is
public void doSomething(Map aMap);
better than
public void doSomething(HashMap aMap);
?
Well if you are doing something that needs a TreeMap and then you want to invoke doSomething, with it, then as long as doSomething takes a Map you are right as rain and never need care. But if doDomething is specific to a HashMap then welcome to pain-town.
Assigning to an interface is always better practice than assigning to an implementation because it gives you more flexibility at no cost.
A practicle example:
I recently refactored one of my old projects and discovered to my joy that using a TreeMap improved performance considerably for some things and a SortedMap was definately the way to go for others. When I first wrote this code I was using Hashtables everywhere. If my methods only accepted Hashtables and not the more generic Map interface then I'd have had many code changes to make. As it is I only had to make a few changes and everything works swimmingly.
The posters above who complain that you have to instantiate the object eventually and thus why not use the implementation all over the place clearly don't get one of the most fundamental (and obvious) OO design patterns at all and I urge them to go read some books.
Admin
You've misunderstood so much of my post that I'm only going to respond to a little of this. Fortunately, your copious swearing is sure to compensate for impaired reading comprehension.
Have you been reading the other posts? Maybe I have a TreeMap or an EnumMap. Or the object returned by Collections.unmodifiableMap (if I don't trust the method to refrain from molesting my map), or Collections.synchronizedMap or Collections.checkedMap.
I'll turn the tables on you. Can you provide a case where a HashMap is acceptable, but other implementations of Map are not?
Non-sequitur? In a paragraph that starts out addressing the various posts which fret over performance?
Running a thousand threads has nothing to do with the impact of slowness?
Admin
True. It's not especially relevant to this WTF. It's a tangent.
But damn, it's an important one. It represents one of the most basic notions of OO, and it's not until the bulk of the world's programmers start getting little things like this that they're going to "get it" on a larger scale. So it's kind of a vendetta for me, and judging from the other posts, for a few others.
Why are we so passionate about it? Because when other programmers do these things, when they really make an opaque, robust API, my job goes about thirty times faster. Because I don't have to spend hours looking through their code trying to figure out what will happen or what a parameter is supposed to be. I can devote my time to getting my own task done!
That does say a lot about the level of the original author's understanding of Java.
I've worked with code which had that, and the String array arguments, and lots of other similar disasters. You have my sympathy.
Admin
If you care about either of those, and you very well may, then taking a Map is incorrect. You can't tell simply by looking at the code, but this is why we have comments and the like.
There are more to interfaces and their implementations than just the methods.
Except that's not true. If doSomething() cares that the Map generally has O(1) retreival instead of O(log n) retreival, then taking a Map is incorrect. You must take a HashMap to retreive that performance guarantee. Having flexibiliy by taking multiple implementations in this case is incorrect.
Admin
How the hell can you have a TreeMap or a EnumMap from this line:
That's the line under discussion. Your response is not only a non-sequitur, it's rather insulting. It's impossible for me to have a TreeMap or an EnumMap, because I have to pick the implementation.
Would be declared as a Map if you did something like this: Simply because that's what the method returns and no other reason.
Non-sequitur. I'm going to be perfectly clear here: We are NOT talking about parameters passed to a function or returned by a method. We're talking about variables being INSTAINIATED AND USED within a method.
Or, are you talking about changing the implementation, after one had already been picked? Well, it still doesn't follow, as I said originally. Best case, you change one extra word. Worse case, you have to rewrite the entire function. But saying: "Map map = new HashMap()" won't save you from that possibility because you could depend on semantics the interface doesn't describe (e.g., performance, implementation details). If you depend on such things, you must rewrite the method anyway if you change from a HashMap to a TreeMap.
Change the type used in the function doesn't save you a thing.
How is this relevant? We're talking about instaniation. I have to pick an implementation. And yes, any case where average O(1) behavior is required for access.
Yes, it literally does not follow.
Not of a single polymorphic method call, no. They can all call foo.SomeMethod() simulatenously and each thread will execute the exact same code. Thread 2 doesn't make a different call or excute different byte/machinecode than Thread 1 than Thread N.
As such, threading and polymorphic method calls have nothing do with each other. They're orthogonal concepts.
Admin
No, if they get this, they'll just continue to produce shit code. This doesn't improve code quality.
This does neither. Implementation details (i.e., method bodies) aren't part of the API by definition. That's what we were talking about.
You don't have to in this case because you know exactly what it is. You don't have to do it anyway, [b]since the method tells you all the types.[b] Complete non-sequitur.
Admin
By pure repetition you're forcing me into believing that "non-sequitur" is the way to write it in the US, is it???
(Yeah, I know, such a totally lame post, I just can't get it out of my system any other way...)
Admin
HashMap carries no performance guarantees (merely average case performance), nor does Map. Everything in Java is hashable (or a primitive, and you can't store them in HashMaps anyway), so HashMap imposes no constraint and provides no guarantees that Map does not.
Taking a Map is going to be correct the overwhelming majority of times.
HashMap has no performance guarantees. If your method needs O(1) retrieval, it cannot use Java's HashMap, because Java's HashMap has no such guarantee. I don't think any general (and so unable to use perfect hashes) hashed container can.
Admin
You're trying to make an invalid (and silly) argument. Average case performance is a performance guarantee.
Also this (from HashMap documentation):
"This implementation provides constant-time performance for the basic operations (get and put), assuming the hash function disperses the elements properly among the buckets."
That sounds like a guarantee to me. You can expect a certain type of performance from a HashMap. You get no such guarantee from Map.
Admin
Ah. Now the source of confusion becomes clear.
We were always talking about the method declaration. At least, I was. And I know at least two other posters were.
I think I even said in my original post that method parameters and return types, as well as variable types, should be of type Map.
I'm pretty sure other posters have pointed out that the two go hand-in-hand: the variable should be of type Map, and the method should accept a parameter of type Map. Together those constitute one of the code's (less prominent) WTFs.
Obviously, if the method's parameter type is HashMap, you have to pass a HashMap (or subclass thereof). Duh.
If I'm suggesting that the variable needs to be of type Map, I am implying that the method needs to accept a parameter of type Map. (Though I believe Aaron has already clarified that the parameter is of type Object and is cast to a HashMap by the method internally. Shudder.)
It's not about saving anything. See my earlier comment on performance and premature optimization.
I was, as I think is now clear, talking about the method. Once the method accepts a parameter of type Map, there is no reason to force a HashMap. I apologize for going forward without making that assumption clear.
Admin
I think most of us would agree that in the general case, it's better for the method to accept Map. It is in fact more generic that way, though genericness may be sacrificed in cases where doing so provides significant benefit. <insert warning about premature optimization>.
However, I think a number of posters (including myself) are unclear as to why the local variable should be declared to be a Map, rather than a HashMap. I see no benefit to this at all.
Admin
Your generally correct on the first two, totally wrong on the third.
Why? It gains you nothing.
No, they're completely orthogonal.
We were (I was anyway) only talking about the variable declaration within the method body. What arguments the method takes and returns are irrelevant to using a HashMap internally, or declaring it as I noted above.
Admin
It's simply a lesser version of the same benefit you get from declaring parameters and return types to be Map.
Perhaps a better way to look at this is to reverse the question: Is there any reason to declare the variable as type HashMap? Does it gain you anything?
</insert>In general, you want to take no more than you need. The less specific you are regarding the type, the less effort it takes to change the implementation used while retaining the same contract for the variable.
Plus, using Map will encourage yourself and other developers to declare their methods to use Map instead of HashMap.
Plus, I've often had to do this when dealing with legacy databases:
enum Season { SPRING, SUMMER, FALL, WINTER };
Map<Integer, Season> dbValuesToSeasons = new TreeMap<Integer, Season>();
dbValuesToSeasons.put(3, Season.SPRING);
dbValuesToSeasons.put(4, Season.SUMMER);
dbValuesToSeasons.put(1, Season.FALL);
dbValuesToSeasons.put(2, Season.WINTER);
dbValuesToSeasons = Collections.unmodifiableMap(dbValuesToSeasons);
I will say that when I'm working, I won't complain if I see a local variable of type HashMap in someone else's code, but I do complain when I see a parameter or return type of type HashMap. If it's private to the method, then it's all implementation details, and as a user of the class I don't care how it does what it does, as long as it does it reliably (or throws an exception).
A code review is a different matter, as the whole point is to strengthen everyone's coding ability by pointing out these things.
Admin
Surely there are 24,335 possible three letter names, which at the rate of 20 per month gives them 101.4 years until the consultants need to come back and suggest they start including numbers.
Admin
Anyone who could really call themselves a programmer would never blame Java. Languages don't kill apps, people do. Now cue the Consultant comments!! [:D]
Admin
I fail to see this. It doesn't make your code any more flexible.
</insert>
No. I think the two cases are equivalent in this situation. Neither is better or worse.
</insert>
I disagree. It's still a one-line change.
This:
<font size="2">"Map map = new HashMap();" => "</font><font size="2">Map map = new TreeMap();"</font>
<font size="2">
</font>Is no easier (or harder) than this:<font size="2">
</font><font size="2">"HashMap map = new HashMap();" => "</font><font size="2">TreeMap map = new TreeMap();"</font>
The only exception to this is when you're using subclass-specific functionality, in which case, you clearly do need the subclass, and the argument is rather moot.
How? Other developers shouldn't be looking into the implementation of your method to decide what interface to expose.
To be honest, I don't believe that you have to do that on a regular basis. This is all internal to a single function. You could just not edit the map. Now, if you're exposing the map, then that's a different issue. At that point, you're talking about interface rather than implementation.
The only way I can see that making sense is if after these lines there are calls to other functions (which you don't trust) which you pass the Map to. In that case, I'll accept this as useful, but changing the variable from "TreeMap </integer,></integer,>dbValuesToSeasons<integer, season=""><integer, season="">" to "Map </integer,></integer,>dbValuesToSeasons<integer, season=""><integer, season="">" is still trivial enough that it doesn't justify making this standard coding practice.
</integer,></integer,>
Admin
26^3 = 17576
However, the other poster should have said 800+ months, not days.
Admin
True. It's more a matter of thinking in terms of the contract rather than the implementation.
From a code maintenance point of view, I agree it's no better or worse.
People copy and paste code. It's an unfortunate, disgusting fact. They also tend to look at your code even when they should only be looking at the javadoc.
When they see that you're only handling variables of type Map, they are more likely to think in terms of objects of type Map. I'd like to think they're more likely to think in terms of objects which adhere to a contract, and not so much objects of a single class.
A lot of programmers also forget that there's other Map implementations. I've met at least eight people in the last year working in Java 1.5 who don't know the EnumMap class exists.
Admin
Coding to the interface makes the code more beautiful. Just look:
;-)
Admin
Sounds like your team members need a refresher course on interface vs. implementation. It also sounds like basic refactoring could fix some of those problems. Even if Joe Random adds a method which accepts HashMap instead of Map, it shouldn't be too much trouble to change it to accept Map later. This kind of stuff inevitably creeps in, and sometimes the only thing to do for it is to devote time to cleaning it up.
Mostly you need to tell Joe to think about the problem rather than digging through code to see what kind of Map to expect.
Admin
Also, I'd never heard of EnumMap, either. I don't think it's reasonable to expect most programmers to know all the classes in the Java library. There are just too many. Also, EnumMap is brand new (came with version 1.5), so it's doubly unlikely that random programmers will be familiar with it.
Admin
Well, the language allows even for this:
The class instantiated may not even have existed at compile-time!
Admin
Not every class, but the java.lang and java.util packages are pretty basic functionality. It's completely reasonable to expect at least an awareness of all the functionality, though I don't feel it requires memorizing every class name.
When one gets a new JDK, the first thing one should do is read the "New Features" section. For 1.5, it's:
http://java.sun.com/j2se/1.5.0/docs/relnotes/features.html
The hour or so it takes to read all that stuff is definitely worth every Java programmer's time. If you have a local copy of the javadoc, this document and nearly all of its links are part of the local document tree.
In particular, notice the "Lang and Util Packages" section.
Admin
I'm afraid I disagree. Threading/concurrency, generics, boxing, foreach, metadata, networking, security, etc. are all important, and all have recieved significant changes/new features or just came into being. I don't think it's it makes a lot of sense to say that changes to java.lang and java.util are necessarily more important than the rest of those changes/additions. I think it's reasonable to expect that programmers have familiarity with the language they're using, but I don't think knowing exactly what's in java.util is especially useful. It's more important to have a good idea of what you can expect to find in java.util. If I found myself needing to create a map with an enum as the key, then I might go looking for it. But I've never, ever needed that functionality. Why should I need to remember that it exists?
And to be fair, the mention of an Enum-specific map implementation is in the "Collections Framework" section.
Admin
This is exactly right.
Admin
I've worked with a database that would only allow a maximum of 5 characters for a tablename and 8 for a fieldname.
Policy was to use 3 and 5 for regular tables and fields, leaving some extra for special purposes (like FK fields, NN resolution tables, etc.).
Admin
And DOS had a limit of 8+3 characters for filenames, which was an improvement over VMS's 6.
People get used to such restrictions and stick to them long after they're gone. They rationalize it to themselves as being efficient.
I work at a company that still has a lot of mainframe technology running. The people who work with it are 60 year old veterans who look at you with a blank expression when you ask about the "interface to the backup securities account database", but immediately know what you mean when you say WP031T.
Admin
Call me nit-picky if you must
OK, I think I will. That change wouldn't affect the behavior of the code, and it wouldn't improve maintainability, either.
Admin
Even when approached from the user's perspective, it's useless. The thing comprises 1400 badly-named tables stored in an SQL Server database, with a horrendous front-end written in Uniface. The licenses we purchase to theoretically keep things going for months typically expire after two weeks. The developers are called out on a weekly basis in order to either fix something, or coerce it into doing something it wasn't designed to do. And then that needs fixing.
Oh noes. This reminds me of a CRM system that had over 1400 tables that had names like xx, prj and ofh. The app looked like it was coded in Visual Basic for Windows 3.1. It crashed often, for example if you pressed cancel when you were supposed to enter your SQL username and password.
Admin
I don't get the 3-letter table name thing. Why would anyone do that?
Clearly, to make it so difficult for any other developers to modify or maintain the code that the consulting company is the only realistic resource, effectively embedding themselves in the client company and guaranteeing a continuous cash flow, at least until the client goes bankrupt, after which said 'Enterprise' consulting company moves on to the next victim. Any questions?
Admin
Hah! That is not nearly Enterprisey enough!
Admin
I was wondering when Oracle Identity Manager (Thor Xellerate) would show up on this site. It is long overdue.