HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

Typesafe heterogeneous container

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
containerheterogeneoustypesafe

Problem

I was reading Joshua Blochs "Effective Java 2nd edition" item 29, which describes how to create Heterogeneous containers, in the end of chapter he wrote:


A Class object used in this fashion is called a type token. You can
also use a custom key type. For example, you could have a DatabaseRow
type representing a database row (the container), and a generic type
Column as its key.

It wondered me and I wrote this implementation which he has mentioned. Is there something I could have done better ? I'm mostly interested in Column class which serves as Type Token

class Column {

    @SuppressWarnings("unchecked")
    public T cast(Object obj) {
        return (T) obj;
    }
}

public class DatabaseRow {

    private Map, Object> row = new HashMap<>();

    public  void putColumn(Column type, T instance) {
        row.put(type, type.cast(instance));
    }

    public  T getColumn(Column type) {
        return type.cast(row.get(type));
    }

    public static void main(String[] args) {
        DatabaseRow db = new DatabaseRow();

        Column colInt = new Column<>();
        Column colDouble = new Column<>();

        db.putColumn(colInt, 1);
        db.putColumn(colDouble, 10.0);

        System.out.println(colInt.getClass() + " " + colDouble.getClass());
        System.out.println(db.getColumn(colInt) + " " + db.getColumn(colDouble));
    }

}

Solution

There are two things I would like to point out here.

-
There is no need to do the cast on the putColumn call. The method signature is: public void putColumn(Column type, T instance) { so we know that instance is of type T already, and it is being stored in an Object value in a Map. There is no reason to force the cast before storing it.

-
The Column's cast method would be better done using a Class instance. Consider the 'standard' pattern of requiring a class instance in the constructor of the Column. For example:

class Column {

    private final Class valClass;
    public Column(Class valClass) {
        this.valClass = valClass;
    }

    public T cast(Object obj) {
        return obj == null ? null : valClass.cast(obj);
    }
}


this has the benefit of not requiring the SuppressWarnings. It also ends up being helpful for other reasons too.

The class would be used as:

Column col = new Column(String.class);


Apart from that, things will be the same.

Code Snippets

class Column<T> {

    private final Class<T> valClass;
    public Column(Class<T> valClass) {
        this.valClass = valClass;
    }

    public T cast(Object obj) {
        return obj == null ? null : valClass.cast(obj);
    }
}
Column<String> col = new Column(String.class);

Context

StackExchange Code Review Q#55737, answer score: 4

Revisions (0)

No revisions yet.