1

I'm trying to do something with generics and I can't seem to figure it out. So I have this interface.

public interface Transformation<A,B> {
    public B transform(A a);
}

And I have a class that implements it.

public class AveragingTransformer implements Transformation<List<Long>,Double> {

    public Double transform(List<Long> a) {
        return a.get(0).doubleValue()/a.get(1);
    }

}

So in my main method I have this...

public static void main(String[] args){
    ....
    Transformation<List<?>,Double> transformation = new AveraginTransformer();
    ....
}

But this doesn't work for some reason, can anyone help me understand why?

EDIT

So the issue is if I want to pass an array to my transformation I can't seem to get the compiler to accept it.

So say I have...

public class foo<T>{

    T val;
    Transformation<? extends List<?>,T> transformation; //This gets initialized by constructor, where I will pass in the averaging transformer in this case.

    public void setVal(List<?> list){
        val = transformation.transform(list);
    }

}

If I try to do this it gives me this error

enter image description here

But I want to keep the left part of my transformation generic because different foos will calculate their values in different ways with potentially different data. i.e. Some foos might calculate their val from a list of Strings but if I provide the right transformer to each, then it should work.

Ryan Stull
  • 1,056
  • 14
  • 35

2 Answers2

3

You must match the generics exactly:

    Transformation<List<Long>,Double> transformation  = new AveragingTransformer();

i.e. change List<?> to List<Long>.

If you want the tool to apply to multiple types then choose an appropriate implemented interface. e.g. here Long implements Number so I will pull back to List<Number>.

public interface Transformation<A, B> {

    public B transform(A a);
}

public class AveragingTransformer implements Transformation<List<Number>, Double> {

    @Override
    public Double transform(List<Number> a) {
        return a.stream().mapToDouble(v -> v.doubleValue()).average().orElse(0);
    }

}

public void test() {
    Transformation<List<Number>, Double> transformation = new AveragingTransformer();
}
OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213
0

Ah so I finally figured it out, as OldCurmudgeon pointed out the issue was the wildcards. The problem was the compiler didn't know that all of them were going to actually be the same in the end, meaning my Foo class actually had another Type parameter I hadn't thought of, the type of the values used to calculate the end result.

public class Foo<T,I>{

    T val;
    Transformation<List<I>,T> transformation;

    public void setVal(List<I> list>){
        val = transformation.transform(list);
    }
}

public static void main(String[] args){
    Foo<Double,Number> foo = nee Foo(new AveragingTransformer());
    List<Number> nums = new Arraylist<Number>();
    nums.add(2);
    nums.add(3);
    foo.setValue(nums);
}

Thanks for pointing me in the right direction!

Ryan Stull
  • 1,056
  • 14
  • 35