I'm doing something wrong but not sure what. Trying to make a lookup map that provides me functions I can call on.
Simple demonstration of the problem:
aa.java
public class aa { /** doesn't matter for this example */}
ab.java
public class ab extends aa { /** doesn't matter for this example */}
Helper.java
public static short[] convert(ab foo)
{
//doesn't matter but eventually returns a short[] i.e.
return new short[5];
}
private interface aaConverterI
{
public <T extends aa> short[] method(Function<T, short[]> in);
}
private static Map<String, aaConverterI> bar = new HashMap<>();
static
{
bar.put("blah", Helper::convert);
}
Compiler says The type Helper does not define convert(Function<T, short[]>) that is applicable here
on the Helper::convert, The method put(String, Helper.aaConverterI) in the type Map<String, aaConverterI> is not applicable for the arguments (String, Helper::convert)
.
If I add a
static Function<ab, short[]> blahFunction = Helper::convert;
There is no complaints about that, and I can change the put to
bar.put("blah", blahFunction);
Which then makes the compiler just complain on the put that The method put(String, Helper.aaConverterI) in the type Map<String, Helper.aaConverterI> is not applicable for the arguments (String, Function<ab, short[]>)
.
I'm missing something but I'm not sure what. Tried adding a @FunctionalInterface
to convert declaration and that didn't change anything.
What am I missing? Thank you!
This interface:
private interface aaConverterI { public <T extends aa> short[] method(Function<T, short[]> in); }
... satisfies the requirements for use as a functional interface. For a method reference to be compatible with this functional interface, its signature must match that of aaConverterI.method()
. That is, it accepts a matching Function
as its argument and returns a short[]
.
This:
public static short[] convert(ab foo)
... does not have such a signature. It accepts an argument of type ab
, which is not a Function
, all other considerations notwithstanding. That explains your error.
I suspect you meant to define aaConverterI
more like this:
private interface aaConverterI
{
public <T extends aa> short[] method(T in);
}
... but even that does not work. aaConverterI.method()
can accept an argument of type aa
or any of its subtypes, but Helper.convert()
cannot accept an argument of type aa
(for example). Note too that aaConverter.method()
is not actually getting anything useful out of its type parameterization. You might as well just perform the erasure manually if that's what you really wanted.
Another, more likely alternative would involve making the interface generic instead of the method:
private interface aaConverterI<T extends aa>
{
public short[] method(T in);
}
... then you could write:
private static Map<String, aaConverterI<? extends aa>> bar = new HashMap<>();
static
{
bar.put("blah", Helper::convert);
}
, but that probably still doesn't help you, because you will find that there is no typesafe way to use any of the methods you pull back out of that map.
Bottom line:
Java generics are not powerful enough to parameterize the Map
you would really like to define, where the keys are (say) Class<?>
and the values are type aaConverterI<the-type-corresponding-to-the-key>
. Your best bet probably is, in fact, the manual erasure:
private interface aaConverterI
{
public short[] method(aa in);
}
, where you write all your converter methods with that exact signature and, yes, cast or Class.cast()
within.