I have to define a List and it has two types of possible values
How can I make a List that is type safe in that it only accepts these two types?
I want to avoid the use of raw List.
A Generic class can have muliple type parameters.
You have to add the numbers as the same type, so you could do x. intValue() + y. intValue(); .
Thus there are four types of lists in Java i.e. Stack, LinkedList, ArrayList, and Vector.
I'm not going to claim that this is a perfect solution, but I'm going to recommend that you go with a "holder" class - also called a "tagged class" by some writers (including Joshua Bloch, who says that tagged classes are "verbose, error-prone, and inefficient").
However, given your situation, I can't see a better way. The solution below provides:
Youd define your holder class like this:
class Holder {
private String foo;
private UserClass bar;
boolean isString;
boolean initialized=false;
Holder (String str) { foo = str; isString=true; }
Holder (UserClass bar) { this.bar = bar; isString=false; }
String getStringVal () {
if (! initialized) throw new IllegalStateException ("not initialized yet");
if (! isString) throw new IllegalStateException ("contents not string");
return foo;
}
// with a similar method for getUserClassVal()
...
}
Another alternative is to use an enum for the tag, rather than the boolean isString - this has the value of being easily extensible to additional types.
Then of course you'd have your compound list:
List samsList = new ArrayList()
Inserts are easy and, as you requested, compile-time type safe:
samsList.add (new Holder(stringVal)); samsList.add (new Holder(userClassVal));
Retrieving values from the list is only slightly more complicated: you have to check the tag (holder.isString()) before deciding which getter to use. As an example, a foreach iteration over the list would look like this:
for (Holder holder: samsList) {
if (holder.isString())
doYourStringProcessing (holder.getStringVal());
else
doYourUserClassProcessing (holder.getUserClassVal());
}
Like I said, I'm not claiming this is perfect, but it meets your requirements will serve your needs and minimize the burden on the caller.
However, I would like to point out that this feels to me as though it's probably cause to consider refactoring/redesign somewhere. One of the guidelines I follow is that whenever I find myself justifying an exception to sound practice, it deserves a lot more thought than simply "how can I do this?".
Here's why: assuming that I'm right that the exception is justified in this case, there's really only two possibilities. One is that the sound practice is incomplete (so that "Prefer X over Y" should be rewritten as "Prefer X over Y except in case Z").
But much more likely is that the underlying clause is an imperfect design, and we should be thinking hard about doing some redesign/refactoring.
Since String is an immediate subclass of Object and is final, you won't find a common supertype between String and your user-defined class other than Object. So List<Object> is what you have to use.
From a design perspective, mixing unrelated classes in a collection is a bad idea. Think about what you're trying to accomplish, and you'll probably come up with a better approach.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With