I want to have a Map object to contain specific value types.
Map<String,Object> foo = new HashMap<String,Object>();
foo.put("1",new Integer(1));
foo.put("2", new String("hello"):
for (Map.Entry<Integer, Integer> entry : foo.entrySet()) {
if(entry.getValue() instanceof String) {
//do something
}
else if(entry.getValue() instanceof Double) {
//throw Exception
}
}
You can see what i am trying to accomplish. I need specific Value types in my Map object so i don't have to put lots of if/else statements. How do i accomplish this ?
If you don't like the idea of having multiple maps, you can use the nice OOP feature called overriding.
see Override Methods for more information.
I would probably use composition pattern to wrap the value types and then define a interface for the action depending of the value types.
public abstract class ValueType {
public abstract void valueSpecificAction();
}
public class DoubleValueType extends ValueType {
private Double value;
public DoubleValueType(Double value) {
this.value = value;
}
public void valueSpecificAction() {
//do double specific actions
}
}
public class StringValueType extends ValueType {
private String value;
public void valueSpecificAction() {
//do string specific actions
}
}
You can then add the objects of type ValueType in the maps.
Map<String,ValueType> foo = new HashMap<String,ValueType>();
foo.put("key1", new DoubleValueType(42.0));
later you can get the value, which has the type ValueType with the public method valueSpecificAction() which do the stuff depending on the specific type.
I don't see how you can avoid to have an if-else somewhere in general.
Jan's solution would spare you the if-else only if the value types can be determine at compulation-time. That is the case in the toy example above but is it so in your actual problem?
If it is a matter of making the code look cleaner you can always hide the if-else and conversions in a set of private methods.
Related
I have the following classes
public class MyCustomFactory extends SomeOther3rdPartyFactory {
// Return our custom behaviour for the 'string' type
#Override
public StringType stringType() {
return new MyCustomStringType();
}
// Return our custom behaviour for the 'int' type
#Override
public IntType intType() {
return new MyCustomIntType();
}
// same for boolean, array, object etc
}
Now, for example, the custom type classes:
public class MyCustomStringType extends StringType {
#Override
public void enrichWithProperty(final SomePropertyObject prop) {
super.enrichWithProperty(prop);
if (prop.getSomeAttribute("attribute01")) {
this.doSomething();
this.doSomethingElse();
}
if (prop.getSomeAttribute("attribute02")) {
this.doSomethingYetAgain();
}
// other properties and actions
}
}
But each custom type class like the string one above might have exactly the same if (prop.getSomeAttribute("blah")) { // same thing; }
Suppose I was to add another attribute, is there a nice way I can avoid having to duplicate if statements in each custom type class that needs it? I can move each if statement to utility class but I still need to add the call to the method in the utility class. I think we can do better.
You can create Map<String, Consumer<MyCustomStringType>>, where the key is your attribute name and value is the method call.
public class MyCustomStringType extends StringType {
private final Map<String, Cosnumer<MyCustomStringType>> map = new HashMap<>();
{
map.put("attribute01", o -> {o.doSomething(); o.doSomethingElse();});
map.put("attribute02", MyCustomStringType::doSomethingYetAgain);
// other properties and actions
}
#Override
public void enrichWithProperty(final SomePropertyObject prop) {
super.enrichWithProperty(prop);
map.entrySet().stream()
.filter(entry -> prop.getSomeAttribute(entry.getKey()))
.forEach(entry -> entry.getValue().accept(MyCustomStringType.this));
}
}
Depending on how you initialise this class (and whether this map is always the same), you might be able to turn in into static final immutable map.
I would also recommend naming it better, but a lot here depends on your domain and what this map and loop actually do.
With the introduction of generics, I am reluctant to perform instanceof or casting as much as possible. But I don't see a way around it in this scenario:
for (CacheableObject<ICacheable> cacheableObject : cacheableObjects) {
ICacheable iCacheable = cacheableObject.getObject();
if (iCacheable instanceof MyObject) {
MyObject myObject = (MyObject) iCacheable;
myObjects.put(myObject.getKey(), myObject);
} else if (iCacheable instanceof OtherObject) {
OtherObject otherObject = (OtherObject) iCacheable;
otherObjects.put(otherObject.getKey(), otherObject);
}
}
In the above code, I know that my ICacheables should only ever be instances of MyObject, or OtherObject, and depending on this I want to put them into 2 separate maps and then perform some processing further down.
I'd be interested if there is another way to do this without my instanceof check.
Thanks
You could use double invocation. No promises it's a better solution, but it's an alternative.
Code Example
import java.util.HashMap;
public class Example {
public static void main(String[] argv) {
Example ex = new Example();
ICacheable[] cacheableObjects = new ICacheable[]{new MyObject(), new OtherObject()};
for (ICacheable iCacheable : cacheableObjects) {
// depending on whether the object is a MyObject or an OtherObject,
// the .put(Example) method will double dispatch to either
// the put(MyObject) or put(OtherObject) method, below
iCacheable.put(ex);
}
System.out.println("myObjects: "+ex.myObjects.size());
System.out.println("otherObjects: "+ex.otherObjects.size());
}
private HashMap<String, MyObject> myObjects = new HashMap<String, MyObject>();
private HashMap<String, OtherObject> otherObjects = new HashMap<String, OtherObject>();
public Example() {
}
public void put(MyObject myObject) {
myObjects.put(myObject.getKey(), myObject);
}
public void put(OtherObject otherObject) {
otherObjects.put(otherObject.getKey(), otherObject);
}
}
interface ICacheable {
public String getKey();
public void put(Example ex);
}
class MyObject implements ICacheable {
public String getKey() {
return "MyObject"+this.hashCode();
}
public void put(Example ex) {
ex.put(this);
}
}
class OtherObject implements ICacheable {
public String getKey() {
return "OtherObject"+this.hashCode();
}
public void put(Example ex) {
ex.put(this);
}
}
The idea here is that - instead of casting or using instanceof - you call the iCacheable object's .put(...) method which passes itself back to the Example object's overloaded methods. Which method is called depends on the type of that object.
See also the Visitor pattern. My code example smells because the ICacheable.put(...) method is incohesive - but using the interfaces defined in the Visitor pattern can clean up that smell.
Why can't I just call this.put(iCacheable) from the Example class?
In Java, overriding is always bound at runtime, but overloading is a little more complicated: dynamic dispatching means that the implementation of a method will be chosen at runtime, but the method's signature is nonetheless determined at compile time. (Check out the Java Language Specification, Chapter 8.4.9 for more info, and also check out the puzzler "Making a Hash of It" on page 137 of the book Java Puzzlers.)
Is there no way to combine the cached objects in each map into one map? Their keys could keep them separated so you could store them in one map. If you can't do that then you could have a
Map<Class,Map<Key,ICacheable>>
then do this:
Map<Class,Map<Key,ICacheable>> cache = ...;
public void cache( ICacheable cacheable ) {
if( cache.containsKey( cacheable.getClass() ) {
cache.put( cacheable.getClass(), new Map<Key,ICacheable>() );
}
cache.get(cacheable.getClass()).put( cacheable.getKey(), cacheable );
}
You can do the following:
Add a method to your ICachableInterface interface that will handle placing the object into one of two Maps, given as arguments to the method.
Implement this method in each of your two implementing classes, having each class decide which Map to put itself in.
Remove the instanceof checks in your for loop, and replace the put method with a call to the new method defined in step 1.
This is not a good design, however, because if you ever have another class that implements this interface, and a third map, then you'll need to pass another Map to your new method.
I have one supertype defined as:
public abstract class AType<T> {
....
private T value;
private T mask;
public T getValue() {
if (isMasking())
return null;
return this.value;
}
public void setValue(T value) {
if (value == null)
throw new IllegalArgumentException("Value is mandatory.");
this.value = value;
}
protected T getMask() {
if (!isMasking())
return null;
return this.mask;
}
protected void setMask(T mask) {
if (mask == null)
throw new IllegalArgumentException("Mask is mandatory.");
this.setMasking(true);
this.mask = mask;
}
...
}
and few subtypes like:
public class SpecType extends AType<Integer> {
...
}
these sub types specifies the unknown parameter.... i have more f.e. IPv4, Long, and so on
now i need to somehow in runtime do a dynamic cast...
i have these classes defined in enum like this:
public enum Type {
SOME_TYPE(new TypeID(0, (short) 0), OFMU16.class,
new Instantiable<AType<?>>() {
#Override
public SpecType instantiate() {
return new SpecType(new OFMatchTypeIdentifier(0, (short) 0));
}
}),...;
...
public Class<? extends AType<?>> toClass() {
return this.clazz;
}
...
}
I want do something like:
AType<?> type = SOME_TYPE.newInstance(); //this works
SOME_TYPE.toClass().cast(type).setValue(10); //this don't work
so I have to do it statically:
((SpecType) type).setValue(10);
Everything would be OK, but the user of this module will not want to look in enum and cast manually every time. This will probably make mistakes and spend a lot of time with debugging :/....
My question is how can I refactor this or how do I define structure of inheritance to allow user to cast dynamically? Is it possible?
Edit:
I am parsing packets from network. There is a lot types which differs in Vendor Type identifier and type of Value/Mask - these fields are all constant for every this combination, so i has defined it as enum constants. F.e. 20 have different only TypeID but same VendorID and all of them can be represented as Integer, next 10 differ in VendorID And TypeID but all of them can be represented as Short and so on.
It's still not clear why you should have to cast at all. As soon as SOME_TYPE is written into your sourcecode OR the type of set setValue method is hardcoded (in your example int or Integer) you don't need runtime checking - you need compile time checking.
So I suppose the following snippet is how your API users should code:
public class TypeTest {
public static void main(String[] args) {
AType<Integer> type0 = Types.SOME_TYPE_0.instantiate();
type0.setValue(10);
AType<String> type1 = Types.SOME_TYPE_1.instantiate();
type1.setValue("foo");
}
}
I have stripped down your example to the bare minimum which is required to understand the Generics part:
abstract class AType<T> {
private T value;
// standard getter/setter
public T getValue() { return this.value; }
public void setValue(T value) { this.value = value; }
}
class SpecTypeInt extends AType<Integer> {
}
class SpecTypeString extends AType<String> {
}
interface Instantiable<T> {
T instantiate();
}
The key part is: Don't use an enum, because an enum cannot have type parameters. You can use a plain interface instead like the next snippet. Each reference in the interface points to a factory. Each factory knows a) the abstract type and b) the concrete type. To make Generics happy you have to glue a) and b) together with ? extends X.
interface Types {
Instantiable<? extends AType<Integer>> SOME_TYPE_0 = new Instantiable<SpecTypeInt>() {
#Override
public SpecTypeInt instantiate() {
return new SpecTypeInt();
}
};
Instantiable<? extends AType<String>> SOME_TYPE_1 = new Instantiable<SpecTypeString>() {
#Override
public SpecTypeString instantiate() {
return new SpecTypeString();
}
} ;
}
Cleanup: Must your user look into the interface: Yes, he must in any case, because he must know which is the appropriate type for setValue 1. NO solution can circumvent this. Although Eclipse might help you and your users a little bit: In main just type Types.SOME_TYPE_1.instantiate(); then go to the start of the line, hit Ctrl2 + L ("Assign to loccal variable") and Eclipse replaces the AType<String> instantiate = part for you.
1If your users don't know the right type for the setValue method, then you are asking the wrong question. In that case you should have asked something like "How to design a Generic safe conversion facility?".
Maybe using a setValue method like this:
public void setValue(Object value) {
if (value == null)
throw new IllegalArgumentException("Value is mandatory.");
this.value = (T)value;
}
Although you will have an unchecked cast.
Hope this helps
How can we restrict the arraylist to accept only a specfic type of object prior to generic
Write a wrapper function that accepts only the allowed type, and hide the collection. That was standard best-practice pre-Java-5.
private final List strings = new ArrayList();
public void add(String s)
{
strings.add(s);
}
public String remove(String s)
{
return (String) strings.remove(s);
}
// etc...
Yes, this sucks.
Might I ask: is there a reason you're not using generics? They are bytecode-compatible with Java 1.4
Two options, (I am assuming C# here, but all applies to pretty much all OO languages).
1) Inherit from collection type of choice (or its interfaces), override all methods to throw exception on wrong type, something like this:
public class MyType
{
// Your type here
}
public class MyTypeCollection : ArrayList
{
public override int Add(object value)
{
if (!(value is MyType))
{
throw new ArgumentException("value must be of type MyType");
}
return base.Add(value);
}
public int Add(MyType myType)
{
return base.Add(myType);
}
// Other overrides here
}
or
2) (probably better), create your own type altogether and implement interfaces as desirable for collections and use a non-generic, non-typed collection internally. Something like this:
public class MyTypeCollection2 : IEnumerable
{
private readonly ArrayList _myList = new ArrayList();
public void Add(MyType myType)
{
_myList.Add(myType);
}
// Other collection methods
public IEnumerator GetEnumerator()
{
yield return _myList.Cast<MyType>();
}
}
Make sure to implement all interfaces you will care about. In the .NET Framework the interfaces implemented for ArrayList are: IList, ICloneable
Hope this helps.
I want to be able to specify a list of keys and allowed values for each key programatically so that the code can be checked at compile time for errors and in the hope of better performance.
Imagine I am representing word in a database and each word has a number of features:
public class Word {
public Map<Feature, FeatureValue> features = new EnumMap<Feature, FeatureValue>();
}
And I have an enum class:
public enum Feature {
TYPE("Type") {
enum Value {
NOUN("Noun"),
VERB("Verb");
}
#Override
public Value[] getValues() {
return new Value[]{Value.NOUN, Value.VERB};
}
},
PLURALITY("Plurality") {
enum Value {
SING("Singular"),
PL("Plural");
}
#Override
public Value[] getValues() {
return new Value[]{Value.SING, Value.PL};
}
},
}
I would at least want to be able to do something like:
word.features.put(TYPE, TYPE.Value.NOUN);
word.features.put(PLURALITY, PLURALITY.Value.PL);
So that it's easy to see that the values match the key, but the enum within enum syntax doesn't seem to be allowed.
I also tried this:
TYPE("Type") {
public String NOUN = "Noun";
public String VERB = "Verb";
but I couldn't reference TYPE.NOUN since they aren't allowed to be static for some reason.
Please is there someone who know a good pattern to specifying something like this? I'm just worried if use strings in my code like
word.features.put(TYPE, "Noun");
I am asking for trouble with typos etc.
You can't do it like that but you can do it like this:
// define a type values as an enum:
enum TypeValue {
Noun, Verb
}
// define an attribute class parametrized by an enum:
public class Attribute<E extends Enum<E>> {
// define your attribute types as static fields inside this class
public static Attribute<TypeValue> Type = new Attribute<TypeValue>();
}
// and now define your method like this:
<E extends Enum<E>, Feature extends Attribute<E>> void put(Feature feature, E value) {
}
// you will then have a compilation error when trying to invoke the method with improper associated parameters.
// eg if we define
enum OtherValue { X }
features.put(Attribute.Type, TypeValue.Noun); // ok
features.put(Attribute.Type, OtherValue.X); // Fails