如何将方法的返回类型声明为传递给该方法的数组中最后一个 lambda 的返回类型



我问一些我认为不可能的事情,如果是,我会删除问题。

I have got method:

public Object convertBy(Function... functions) {
}

,这些函数是:

interface FLines extends Function {
    @Override
    default Object apply(Object t) {
        return null;
    };
    public List<String> getLines(String fileName);
}
interface Join extends Function {
    @Override
    default Object apply(Object t) {
        return null;
    };
    public String join(List<String> lines);//lines to join
}
interface CollectInts extends Function {
    @Override
    default Object apply(Object t) {
        return null;
    };
    public List<Integer> collectInts(String s);
}
interface Sum<T, R> extends Function<T, R> {
    @Override
    default Object apply(Object t) {
        return null;
    };
    public R sum(T list);//list of Integers
}

这些接口中的抽象方法返回不同类型的值。我将lambda传递给我的convertBy方法。

我想设置convertBy的返回类型与functions[functions.length - 1]的返回类型相同。

这可能吗?


编辑:

我已经改变了方法的签名和接口内部方法的签名。它是有效的,但只有当我在下面张贴的主要标记的地方铸造。它只需要在4个方法调用中的3个中强制转换的奇怪的东西,我想在main中完全摆脱强制转换。

import java.util.List;
import java.util.function.Function;

public class InputConverter<T> {
    private T value;
    public InputConverter(T value) {
        this.value = value;
    }

    public <T, R> R convertBy(Function<T, R> special, Function... functions) { 
        if (functions.length == 0) {
            FLines flines = (FLines) special;
            return (R) flines.getLines((value instanceof String) ? (String) value : null);
        } else if (functions.length == 1) {
            FLines flines = (FLines) functions[0];
            Join join = (Join) special;
            return (R) join.join(flines.getLines((String) value));
        } else if (functions.length == 2) {
            if (functions[0] instanceof FLines) {
                FLines flines = (FLines) functions[0];
                Join join = (Join) functions[1];
                CollectInts collectInts = (CollectInts) special;
                return (R) collectInts.collectInts(join.join(flines.getLines((String) value)));
            } else {
                Join join = (Join) functions[0];
                CollectInts collectInts = (CollectInts) functions[1];
                Sum sum = (Sum) special;
                return (R) sum.sum(collectInts.collectInts(join.join((List<String>) value)));
            }
        } else {
            FLines flines = (FLines) functions[0];
            Join join = (Join) functions[1];
            CollectInts collectInts = (CollectInts) functions[2];
            Sum sum = (Sum) special;
            return (R) sum.sum(collectInts.collectInts(join.join(flines.getLines((String) value))));
        }
    }
    /*  public Integer convertBy(Join join, CollectInts collectInts, Sum sum) {
            return sum.sum(collectInts.collectInts(join.join((List<String>) value)));
        }*/
}
interface FLines<T, R> extends Function {
    @Override
    default Object apply(Object t) {
        return null;
    };
    public R getLines(T fileName);
//  public List<String> getLines(String fileName);
}
interface Join<T,R> extends Function {
    @Override
    default Object apply(Object t) {
        return null;
    };
    public R join(T lines);//lines to join
//  public String join(List<String> lines);//lines to join
}
interface CollectInts<T, R> extends Function {
    @Override
    default Object apply(Object t) {
        return null;
    };
    public R collectInts(T t);
//  public List<Integer> collectInts(String s);
}
interface Sum<T, R> extends Function<T, R> {
    @Override
    default Object apply(Object t) {
        return null;
    };
    public R sum(T list);//list of Integers
}

主方法:

   FLines<String, List<String>> flines ....
  Join<List<String>, String> join ...
  CollectInts<String, List<Integer>> collectInts ...
    Sum<List<Integer>, Integer> sum ...
String fname =/* System.getProperty("user.home") + "/*/ "LamComFile.txt"; 
InputConverter<String> fileConv = new InputConverter<>(fname);
List<String> lines =  fileConv.convertBy(flines);//cannot cast from Object to List<String>
String text =  fileConv.convertBy( join, flines);//cannot cast from Object to String
List<Integer> ints =   fileConv.convertBy(collectInts,flines, join);//cannot cast from Object to List<Integer>
Integer sumints =  fileConv.convertBy(sum, flines, join, collectInts);//works without cast!

我不明白为什么编译器理解sum返回,但不推断例如collectInts返回。

看来你对泛型类型层次结构有一些误解。当您想要扩展泛型类型时,您必须对扩展类或接口的实际类型做出基本决定。您可以像

那样指定确切的类型
interface StringTransformer extends Function<String,String> {}

(这里我们创建了一个扩展泛型类型但不是泛型本身的类型)

或者您可以创建一个泛型类型,它使用自己的类型参数来指定超类的实际类型参数:

interface NumberFunc<N extends Number> extends Function<N,N> {}

注意,我们如何创建一个新的类型参数N,它有自己的约束,并使用它来参数化超类,要求它的类型参数与我们的相匹配。

相反,当您声明像

这样的类时,
interface FLines<T, R> extends Function

您正在扩展原始类型Function并创建新的类型参数<T, R>,这在您的场景中完全无用。

继续上面的例子,你可以将它们实现为

StringTransformer reverse = s -> new StringBuilder(s).reverse().toString();
NumberFunc<Integer> dbl = i -> i*2;

,因为它们继承了正确类型的方法,所以可以使用它们来组合函数:

Function<String,Integer> f = reverse.andThen(Integer::valueOf).andThen(dbl);
System.out.println(f.apply("1234"));

将此应用到您的场景中,您可以定义如下接口
interface FLines extends Function<String,List<String>> {
    @Override default List<String> apply(String fileName) {
        return getLines(fileName);
    }        
    public List<String> getLines(String fileName);
}
interface Join extends Function<List<String>,String> {
    @Override default String apply(List<String> lines) {
        return join(lines);
    }
    public String join(List<String> lines);
}
interface CollectInts extends Function<String,List<Integer>> {
    @Override default List<Integer> apply(String s) {
        return collectInts(s);
    }
    public List<Integer> collectInts(String s);
}
interface Sum extends Function<List<Integer>, Integer> {
    @Override default Integer apply(List<Integer> list) {
        return sum(list);
    }
    public Integer sum(List<Integer> list);
}

和重新设计你的InputConverter只接受一个函数,可能是一个组合函数:

public class InputConverter<T> {
    private T value;
    public InputConverter(T value) {
        this.value = value;
    }
    public <R> R convertBy(Function<? super T, ? extends R> f) {
        return f.apply(value);
    }
}

可以以类型安全的方式使用:

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<String> fileConv = new InputConverter<>("LamComFile.txt");
List<String> lines = fileConv.convertBy(flines);
String text = fileConv.convertBy(flines.andThen(join));
List<Integer> ints = fileConv.convertBy(flines.andThen(join).andThen(collectInts));
Integer sumints = fileConv.convertBy(
    flines.andThen(join).andThen(collectInts).andThen(sum)
);

您必须更改方法签名并内联最后一个变量值作为单独的参数。

如果你把这个参数作为最后一个,那么你就不能使用变量参数,因为它总是最后一个,必须用数组来表示,以防它不是最后一个:

public <T, R> R convertBy(Function[] functions, Function<T, R> special) { }

但是,如果您坚持使用变量,那么您可以移动"特殊"Function作为第一个参数:

public <T, R> R convertBy(Function<T, R> special, Function... functions) { }

感谢所有详细阐述这个主题的人,你们的解决方案在现实世界中要好得多。

作为作者,我想发布我的解决方案,使convertBy()的调用不改变为main()位。它很短,很丑,但很有效。

Main:

Function<String, List<String>> flines ... lambda here
Function<List<String>, String> join ... lambda here
Function<String, List<Integer>> collectInts ... lambda here
Function<List<Integer>, Integer> sum ... lambda here

String fname = System.getProperty("user.home") + "/LamComFile.txt"; 
InputConverter<String> fileConv = new InputConverter<>(fname);
List<String> lines = fileConv.convertBy(flines);
String text = fileConv.convertBy(flines, join);
List<Integer> ints = fileConv.convertBy(flines, join, collectInts);
Integer sumints = fileConv.convertBy(flines, join, collectInts, sum);
System.out.println(lines);
System.out.println(text);
System.out.println(ints);
System.out.println(sumints);
List<String> arglist = Arrays.asList(args);
InputConverter<List<String>> slistConv = new InputConverter<>(arglist);  
sumints = slistConv.convertBy(join, collectInts, sum);
System.out.println(sumints); 

InputConverter类:

public class InputConverter<T> {
    private T value;
    public InputConverter(T value) {
        this.value = value;
    }
    public <T, R> R convertBy(Function... functions) {
        Object result = value;
        for (int i = 0; i < functions.length; i++) {
            result = functions[i].apply(result);
        }
        return (R) result;
    }
}

最新更新