Reputation: 103797
I'm writing a method that forms part of the public interface of a Java class. It broadly allows the caller to specify the values to assign to a number of database entities - so they must supply both the IDs of the entities themselves, and the values to assign to them.
I'm wavering between implementing this as a List<Pair<Integer, Integer>>
or just two List<Integer>
arguments. Both would obviously work, and neither would cause any implementation or efficiency problems within my method. It's basically the same information in any case (a 2xn array), just striped differently.
So I'd like some opinions on which one you think would be better, and why.
Advantages I see so far for the list of pairs:
Advantages for the pair of lists:
Pair
is to grasp as a concept)Both cases have identical type-safety, as well as the same possibility for argument mismatch (e.g. entering values first and IDs second when it should be the other way around). This latter problem can be avoided by creating a trivial wrapper around Integer
called something like PrimaryKey
, which has its own pros and cons and is orthogonal to this issue anyway as this can be used just as well in both cases.
However there's a middle ground that could feasibly be a third option - a trivial container class with integer fields for objectId and value. This doesn't enlist the compiler's help in ensuring the objects are correct through typing, but it does provide an extra layer of security in the assignments. I don't think I'd go for this, though, as I don't like the idea of polluting a public interface with a trivial class like this.
Upvotes: 7
Views: 5108
Reputation: 308763
Go with the List of Pairs or a Map.
I'm not buying any of the "con" arguments you listed.
You should always err on the side of greater abstraction. You're writing an object-oriented language, and encapsulation and information hiding are, in my opinion, the most important reason for thinking in objects. It hides implementation details from users, letting them concentrate on what your class provides. They can forget about how your class accomplishes what they want. Forcing your clients to maintain two lists is asking them to know more than they need to.
Upvotes: 0
Reputation: 48629
I half-disagree with this point:
because although there is no Pair
class in the JDK, there is an interface: Map.Entry
which fits your intended use as a key/value association.
Upvotes: 1
Reputation: 36987
You might consider making the parameter an Iterator<Pair>
. If the calling class has a List<Pair>
, getting the iterator is trivial. If not, creating the iterator might be easier to construct, faster and/or more natural. In some cases, it might even help you eliminiating out-of-memory problems.
Upvotes: 0
Reputation: 75376
Write the unit tests first. Then you can easily see what is easiest to work with, and then choose that as your implementation.
Upvotes: 0
Reputation: 7388
The list-of-pairs approach is the obvious thing to do, as it more accurately reflects the intention -- but a Map might be even better, if the IDs are unique.
If you have millions of these pairs, and memory consumption becomes a major consideration, you might want to switch to pairs-of-lists (since there will be one less object per pair).
Upvotes: 3
Reputation: 70324
Why not go with a Dictionary (map type, whatever Java calls it nowadays, I think it used to be Hashtable
)? This would map IDs to values and sidesteps your dilemma.
Upvotes: 6
Reputation: 272297
I would strongly recommend tying that data together, possibly as a Pair, but more as a specific container. That way you're at liberty to introduce extra functionality related to those two objects.
Keeping the two lists separate is going to be a pain. You'll have to pass both around together and keep them in sync. The overhead of creating a new object for this is negligible, and precisely what OOP is designed for (you'll be creaing non-JDK classes just by writing new Java code for your application, don't forget).
I create minor classes like this all the time. They enforce strong type safety and provide the scope for enhancement and refactoring. IDEs can more readily identify and perform refactorings.
Upvotes: 24
Reputation: 160964
I feel that the analysis you've gone through already identifies the pros and cons of the two methods very well.
I would also lean towards using the Pair
class, citing the advantages that you've listed:
- More accurately reflects the actual relationship between the entities
- Eliminates some classes of dynamic error (e.g. mismatched list lengths)
The big one for me would the top one.
Always write code which demonstrates the intent. Don't code by thinking solely about the implementation.
Using an class like Pair
shows the intent that there is a pair of values which represents an ID and the actual entity itself. It also shows that one Pair
object is one discrete unit of data which needs to be handled together -- something that cannot be infered from having two separate List
s of IDs and entities.
Upvotes: 6
Reputation: 206816
I would go for the List
of Pair
s, if the two integers really belong together and are supposed to represent "one thing".
Another disadvantage of using two separate lists is that the compiler doesn't check for you if the lists are always the same size. And you leave the interpretation up to the client of your method; the client needs to match up the elements in the two lists.
I don't see using a class like Pair
as a big disadvantage "because it relies on non-JDK classes", as you say, but if you really don't want to use something like Pair
, you could even make it a list of arrays: List<Integer[]>
, where each array contains the two Integer
objects. (In my opinion that's uglier than using Pair
).
Upvotes: 3
Reputation: 27632
In my opinion, go with the list of pairs (or your own more specific container) since this seems to be what most naturally reflects the problem you are solving. And it is only one variable to keep track of, and send to methods, instead of two.
Upvotes: 0
Reputation: 193
When the API is public make sure you just implement the core functionality because everything you give to a client can never be taken back.
Think about a method with just 2 Parameters assign(Integer entityId, Integer someOtherId) and let the client figure it out how to add more items.
If you want to allow convenient acces give them a util class that comes with an interface "Assignment" which just defines getEntityId() and getSomeOtherId() and with a default implementation like DefaultAssignment which holds final references to the ids.
Then your clients can choose which way they want to go and you dont have to make sure to support your "Pair" class.
Upvotes: 3