开发者

How can I store Java types, allowing only some specific ones?

Lets assume I want to have a class that acts a descriptor for records, where each record has a set of attributes.

Each attribute has a unique name and should have a specific type that corresponds to a certain Java type such as Integer, String, Short, Double, ...

The list of possible types should be restricted such as I support only Integer and String for instance.

private HashMap<String, Class> attributeList = new HashMap<String, Class>();

In the开发者_运维问答 above example the HashMap is a list of attributes where as the key is the attribute name and the value should be the type of the attribute (Integer or String).

What would be the best way to restrict the definition of the value of the Hashmap?


You could of course use wrapper methods to add elements to the map, and do a check for Integer and Sring there. But then you only get runtime errors. I agree with you that restricting the type to get static errors is much better.

For that, I would actually not use Integer.class and String.class, but an enum:

enum Types { String, Integer };

private Map<String, Types> attributeList = new HashMap<String, Types>();

UPDATE:

Come to think of it, there is another (but more complicated) solution, if you have to stick to Class objects: You can use the fake enum pattern, that is use a set of constants (usually the integers 2^i are used) like an enum. So you could define your Class objects as the constants. That of course does not guarantee that no other class objects are put into the map. That's why Joshua Bloch item 30 says "Use enums instead of int constants". But you can then use the Checker Framework to pull an additional type system over your constants using the Fake Enum checker:

@SuppressWarnings("fenum:assignment.type.incompatible")
public class TypeEnum {
  public static final @Fenum("Types") Class INT_CONST = Integer.class;
  public static final @Fenum("Types") Class STR_CONST = String.class;
}

Then you can define your map with a restriction on the type Class:

private HashMap<String, @Fenum("Types") Class> attributeList
   = new HashMap<String, @Fenum("Types") Class>();

Of course, you would need to include the Fenum Checker into your compiler.


How about subclass HashMap and override the put method, throwing an exception when an unsupported type is used? (Untested... just off the top of my head.)

class MyAttributes extends HashMap<String, Class> {
    private Set<Class> allowedTypes;

    public MyAttributes() {
        allowedTypes = new HashSet<Class>();
        allowedTypes.add(Integer.class);
    }
    public Class put(String key, Class value) {
        if(!allowedTypes.contains(value)) {
            throw new UnsupportedTypeException(); // <-- Your new exception type.
        }
        return super.put(key, value);
    }
}


As I see it, you have three options:

  1. Use the definition as you have it, and when you pull the value check that it's one of the correct types.
  2. Subclass the HashMap and enforce the type limits in said subclass when adding the elements.
  3. Have multiple maps, one for each type you want to allow, typed appropriately.

Each option has advantages and disadvantages, and which one you should use should be determined by how you will use it.


How about method overload?

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;

public class CarrierDate<T> {

    private T localDate;

    private CarrierDate(T localDate) {
        this.localDate = localDate;
    }

    public T getLocalDate() {
        return localDate;
    }

    public static CarrierDate<LocalDate> instance(LocalDate date) {
        return new CarrierDate<>(date);
    }

    public static CarrierDate<LocalDateTime> instance(LocalDateTime date) {
        return new CarrierDate<>(date);
    }

    public static CarrierDate<OffsetDateTime> instance(OffsetDateTime date) {
        return new CarrierDate<>(date);
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜