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