Implement一个泛型解析器类



我想写一个通用的excel解析器类。但是向其传递函数存在问题

解析器读取excel行,并从每一行创建一个对象。通过系统视图,它获得了一个excel文件、一个类以及每列与对象字段之间的映射(它的setter函数),并生成了一个对象列表。

如果我们为每个pojo创建一个Parser(Studentpojo为StudentParserSchoolSchoolParser),那么在这些解析器中会有很多重复。因此,需要实现一个通用的Parser类,但我不知道如何将setter方法传递给该类。我们需要这样的东西:

private Map<Integer, java.util.function.Consumer> mapColumnIndexToSetter = new HashMap<>();
mapColumnIndexToSetter .put(3, Student::setName);

Student::setName出现错误:

Error:(30, 41) java: incompatible types: invalid method reference
incompatible types: java.lang.Object cannot be converted to java.lang.String`

我知道上面的代码不能满足我的要求。但它给出了一些关于需求的概念。

关于这个通用Parser类在java8:中的实现,我有两个问题

  1. 如何将类和setter方法传递给解析器类
  2. 如何新建一个泛型类(调用其构造函数)并使用上面提到的setter设置其字段

Student.setName(String)这样的方法需要两个参数,一个是Student实例调用方法,另一个是传递String。因此,一个合适的功能接口将是BiConsumer<Student,String>

顺便说一句,excel表的列很少稀疏到足以证明从索引到函数使用HashMap是合理的。具有针对每一列的函数的CCD_ 14是直接的。

要实例化类型,可以使用Supplier

把它放在一起,这样一个类可能看起来像

public class Parser<T> {
public static final BiConsumer<Object,Object> IGNORE = (x,y) -> {};
private final Supplier<? extends T> instantiator;
private final List<BiConsumer<? super T, ? super String>> setters;
public Parser(Supplier<? extends T> instantiator,
List<BiConsumer<? super T, ? super String>> setters) {
this.instantiator = Objects.requireNonNull(instantiator);
this.setters = new ArrayList<>(setters);
if(this.setters.contains(null)) throw new NullPointerException();
}
public Parser(Supplier<? extends T> instantiator,
BiConsumer<? super T, ? super String>... setters) {
this(instantiator, Arrays.asList(setters));
}
// Replace the two-dimensional string array with actual xls parsing...
public List<T> parse(String[][] data) {
List<T> result = new ArrayList<>(data.length);
for(String[] row: data) {
T instance = instantiator.get();
for (int ix = 0; ix < row.length; ix++)
setters.get(ix).accept(instance, row[ix]);
result.add(instance);
}
return result;
}
}

然后,要仅使用第3列初始化Students的名称,可以使用

Parser<Student> parser = new Parser<>(Student::new,
Parser.IGNORE, Parser.IGNORE, Student::setName);
List<Student> list = parser.parse(new String[][] {
{null,         null,          "Moe" },
{null,         null,          "Larry" },
{null,         null,          "Curly" },
});
list.forEach(System.out::println);
您正在传递的FunctionMap's声明不兼容。

Map声明中,您没有为Function指定泛型类型参数,因此这些参数将推断如下:

Function<Object, Object>

另一方面,你正在通过:

// I guess getName() is returning a String
Function<Student, String> function = Student::getName;

现在,除非另有规定,否则此类引用中的泛型类型参数必须完全匹配,如下所示:

Function<? extends Object, ? extends Object>

只要你能从Function调用中获得Objectextends Object显然毫无意义,所以它可以简化为:

Function<?, ?>

但您也可以在这里添加一个通用限制,例如:

Function<?, ? extends Serializable>

相关内容

最新更新