I ask for something which I see impossible and I\'ll delete question if it is.
I have got method:
public Object convertBy(Function... functions) {
}
It seems, you have some misunderstanding about generic type hierarchies. When you want to extend a generic type, you have to make a fundamental decision about the actual types of the extended class or interface. You may specify exact types like in
interface StringTransformer extends Function {}
(here we create a type that extends a generic type but is not generic itself)
or you can create a generic type which uses its own type parameter for specifying the actual type argument of the super class:
interface NumberFunc extends Function {}
Note, how we create a new type parameter N with its own constraints and use it to parametrize the superclass to require its type parameters to match ours.
In contrast, when you declare a class like
interface FLines extends Function
you are extending the raw type Function and create new type parameters which are entirely useless in your scenario.
To stay at the above examples, you may implement them as
StringTransformer reverse = s -> new StringBuilder(s).reverse().toString();
NumberFunc dbl = i -> i*2;
and since they inherit properly typed methods, you may use these to combine the functions:
Function f = reverse.andThen(Integer::valueOf).andThen(dbl);
System.out.println(f.apply("1234"));
Applying this to your scenario, you could define the interfaces like
interface FLines extends Function> {
@Override default List apply(String fileName) {
return getLines(fileName);
}
public List getLines(String fileName);
}
interface Join extends Function,String> {
@Override default String apply(List lines) {
return join(lines);
}
public String join(List lines);
}
interface CollectInts extends Function> {
@Override default List apply(String s) {
return collectInts(s);
}
public List collectInts(String s);
}
interface Sum extends Function, Integer> {
@Override default Integer apply(List list) {
return sum(list);
}
public Integer sum(List list);
}
and redesign your InputConverter to accept only one function which may be a combined function:
public class InputConverter {
private T value;
public InputConverter(T value) {
this.value = value;
}
public R convertBy(Function super T, ? extends R> f) {
return f.apply(value);
}
}
This can be used in a type safe manner:
FLines flines = name -> {
try { return Files.readAllLines(Paths.get(name)); }
catch(IOException ex) { throw new UncheckedIOException(ex); }
};
Join join = list -> String.join(",", list);
CollectInts collectInts=
s -> Arrays.stream(s.split(",")).map(Integer::parseInt).collect(Collectors.toList());
Sum sum = l -> l.stream().reduce(0, Integer::sum);
InputConverter fileConv = new InputConverter<>("LamComFile.txt");
List lines = fileConv.convertBy(flines);
String text = fileConv.convertBy(flines.andThen(join));
List ints = fileConv.convertBy(flines.andThen(join).andThen(collectInts));
Integer sumints = fileConv.convertBy(
flines.andThen(join).andThen(collectInts).andThen(sum)
);