Java: Reading data with type that isn't known in advance

Question!

I'm working on a project in which I have to read a bunch of features (properties) from a database (which is in the form of a CSV file).

This is how the file looks (formatted a bit for easier readability):

IsFast; Speed; IsRed;   R;   G;   B
     T; 123.4;     F; 0.0; 0.0; 1.0
     F;  21.3;     T; 1.0; 0.0; 0.0
...

As you can see, T/F represent boolean values, while numbers are floating point values. Properties may later be added or removed.

In my code I need to read these values for each instance (row) and then pass them to other code which then processes the data further.

The way I'm currently dealing with this is to have the following classes:

public abstract class Feature<T> {
    public final String name;
    public final T value;

    public Feature(String name, T value) {
        this.name = name;
        this.value = value;
    }

    public abstract boolean test(T value);
}



public class BoolFeature extends Feature<Boolean> {
    public BoolFeature(String name, boolean value) {
        super(name, value);
    }

    @Override
    public boolean test(Boolean value) {
        return this.value;
    }
}



public class DoubleFeature extends Feature<Double> {
    public DoubleFeature(String name, double value) {
        super(name, value);
    }

    @Override
    public boolean test(Double value) {
        return this.value < value;
    }
}

I'm then parsing the CSV file and creating BoolFeature objects for input that's T/F and DoubleFeatures for others, saving it all in a List<Feature> or Feature[], and then passing that collection around.

This however results in a lot of

Feature is a raw type. References to generic type Feature should be parameterized

and

Type safety: The method test(Object) belongs to the raw type Feature. References to generic type Feature should be parameterized

in code like:

public abstract class Metric {
    protected List<Feature> features;      // this line gives warning #1 from above

    public Metric(List<Feature> features) {
        this.features = features;
    }

    public double getSplitQuality(Split split) {
        return getImpurity(split.yes) + getImpurity(split.no);
    }

    public abstract double getImpurity(List<Instance> instances);
}

public class Split {
    public final List<Instance> yes;
    public final List<Instance> no;

    public Split(List<Instance> instances, Feature feature) {
        yes = new ArrayList<>();
        no = new ArrayList<>();
        for (Instance inst : instances)
            if (inst.features.get(feature.name).test(feature.value))   // this line gives warning #2 from above
                yes.add(inst);
            else
                no.add(inst);
    }
}

public class Instance {
    public HashMap<String, Feature> features = new HashMap<>();
    public String output = null;

    public Instance(String[] featureNames, String[] csvRow) {
        /* parse CSV row, creating BoolFeatures and DoubleFeatures
           and adding them to the HashMap, for example: */
        if (csvRow[0].equals("T") || csvRow[0].equals("F"))
            features.put(featureNames[0], new BoolFeature(featureNames[0], csvRow[0].equals("T")));
    }
}

Is there a cleaner way to deal with a problem like this?

EDIT

After adding the <?> to all references to Feature, as per the answer, the line that previously gave warning #2 now gives a compile time error:

The method test(capture#2-of ?) in the type Feature is not applicable for the arguments (capture#3-of ?)



Answers
Your List<Feature> uses the raw-type Feature (as the warning says). If you know what subtype Feature has you can use the generic type e.g List<Feature<Boolean>>.

However if you want your List<Feature to contain BoolFeature and DoubleFeature you can make use of the wildcard-type like List<Feature<?>>

By : recke96


Did your Feature even compile? I doubt since you didn't declare T. How about this?

public abstract  class Feature<T> {
public final String name;
public final T value;

public Feature(String name, T value) {
    this.name = name;
    this.value = value;
}

public abstract boolean test(T value);

}

I don't have any warning in my eclipse with any 3 classes anymore.



This video can help you solving your question :)
By: admin