views:

216

answers:

4

So, I have a situation where I need to pass in three values into a serial BlockingQueue queue:

(SelectableChannel, ComponentSocketBasis, Integer).

They don't actually need to be hash mapped at all, and to use a HashMap is ridiculous as there will always be only one key for each entry; it'd be fine if they were just in some sort of ordered set. For lack of a known alternative, however, I used a HashMap in my implementation and produced this obfuscated generics composition:

private LinkedBlockingQueue<HashMap<HashMap<SelectableChannel, ComponentSocketBasis>, Integer>> deferredPollQueue = new LinkedBlockingQueue<HashMap<HashMap<SelectableChannel, ComponentSocketBasis>, Integer>>();

This seems really ridiculous. I must be a terrible n00b. Surely there is a better way to do this that doesn't require me to decompose the key when retrieving the values or waste the (theoretical--in practice, Java's always bloated :) algorithmic complexity on a useless hash computation I don't need because I have a key space of 1 and don't even want to relationally map the three references, but merely to group them? With this implementation, I have to pull out the values thusly:

while(deferredPollQueue.size() > 0) {
    System.out.println("*** Draining new socket channel from queue");
    HashMap<HashMap<SelectableChannel, ComponentSocketBasis>, Integer> p = deferredPollQueue.take();

    SelectableChannel chan = null;
    ComponentSocketBasis sock = null;
    int ops = 0;

    HashMap<SelectableChannel, ComponentSocketBasis> q = p.keySet().iterator().next();

    chan = q.keySet().iterator().next();
    sock = q.get(chan);

    ops = p.get(q).intValue();

    SelectionKey k = chan.register(selector, ops);  

    if(!channelSupervisorMap.containsKey(k))
        channelSupervisorMap.put(k, sock);
}

I am pretty sure every being capable of sentient reason here probably thinks this is a ridiculous way to do it, so the question is - what's the right way? :) I can't find evidence of a java.util.Pair or java.util.Triplet anywhere.

I suppose an Orthodox Way(TM) would be to do a custom class or interface just for the purpose of housing this triplet, but for such a small task in such a large system this seems preposterously verbose and unecessary--though, then again, that's Java itself.

By the same token, perhaps the values can be put onto an ArrayList or a Vector or derivative thereof, but in Java this does not yield a more terse way of addressing them than I'm getting out of this HashMap here, though it does solve the algorithmic complexity issue perhaps.

Back in Perl land, we'd just do this by using an array reference as a value inside an array:

push(@$big_queue_array, [$elem1, \%elem2, \@elem3]);

What's the best equivalent in Java?

+5  A: 

Why not just create your own generic Pair or Triple classes? Pretty much every Java 5+ project ends up having them in their own util classes!

JeeBee
Seriously? This is considered kosher? :)Sorry, C and Perl guy here -- just trying to figure things out.
Alex Balashov
Yes, a Generic Pair is one of the examples on http://en.wikipedia.org/wiki/Generics_in_Java although they forgot to override equals and hashcode.
JeeBee
So in your code, you would have "private LinkedBlockingQueue<Triplet<SelectableChannel, ComponentSocketBasis, Integer>> foo;". However there is nothing wrong in creating a concrete class with the three members and have sane method names like "getSelectableChannel()" instead of "getFirst()" like you would have with Pair/Triplet.
JeeBee
JeeBee: So, which approach is methodologically "better?" Why?
Alex Balashov
If those three objects together are a common item of data, then I'd have a specific class. If they only exist in one part of the system, especially within a single class, the Triplet suffices. If you use Triplet elsewhere in your system, then at least the code is being reused. If you might add more fields later on then creating a specific class gets more desirable. If it is visible at the API level then the specific class is again desirable (and commented nicer for API docs).
JeeBee
+3  A: 

You say that a custom class to hold the triplet would be bloated and unnecessary, but this really is the way to do it, that's how object-oriented modelling works. A custom class is explicit and readable, and takes up no more runtime resources than a generic holder class would.

skaffman
That's what I suspected, but didn't want to do. Sorry, newbie here. Didn't want to end up on TheDailyWTF or something.In light of that, do you think I should create a custom triplet class specifically for holding these values in this situation, or do as the comment above you suggests and create a generic Pair and/or Triplet class with Object references?
Alex Balashov
I'd create a custom class, for the reasons iterated above - readability is king, my friend.
skaffman
This may ultimately be a pointless aesthetic sort of argument, but it really seems like a 3-element Triplet generic would be easier to read and far more terse ...
Alex Balashov
+1  A: 

Functional Java has pairs, triplets, and tuples up to arity 8. There's also a type called HList for arbitary arity. So your type would be:

LinkedBlockingQueue<P3<SelectableChannel, ComponentSocketBasis, Integer>>

This is just a library, so drop the jar in your classpath and you're good to go.

Apocalisp
+1  A: 

You could just use an ArrayList to store the objects, since you know which object will be at which location. Creating a new class with the members SelectableChannel and ComponentSocketBasis for the would probably be better.

If you're going to be doing this kind of thing a lot, creating a generic pair or tuple now will save you a lot of time, but if this is the only place you're going to be using it, then creating a new class will result in much easier to read code.

Whenever you see your classname in the code, you'll know exactly what it's for, whereas if you just see your generic amalgamation, it might be harder for you (or someone else) to make sense of what it's being used for.

It's a tradeoff between programming time and readability.

Chad Okere