[英]Impelement a generic parser class
我想編寫一個通用的excel解析器類。 但是將函數傳遞給它有一個問題。
解析器讀取excel行並從每行創建一個對象。 通過系統視圖,它將獲得一個excel文件,一個類以及每個列與一個對象字段(其setter函數)之間的映射,並生成一個對象列表。
如果我們為每個pojo創建一個Parser
( Student
StudentParser
用於Student
pojo, SchoolParser
用於School
),則這些解析器中有很多重復項。 因此,需要實現通用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`
我知道上面的代碼不能滿足我的要求。 但是它給出了一些關於需求的想法。
關於在Java 8中實現此通用Parser
類,我有兩個問題:
您傳遞的Function
與Map'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
調用中獲取Object
, extends Object
顯然毫無意義,因此可以簡化為:
Function<?, ?>
但是您最好在此處添加一個通用限制,例如:
Function<?, ? extends Serializable>
像Student.setName(String)
這樣的方法需要兩個參數, Student
實例用於調用該方法,而String
傳遞。 因此,適當的功能接口應為BiConsumer<Student,String>
。
順便說一句,excel表的列很少稀疏到可以證明從索引到函數使用HashMap
是合理的。 具有針對每一列的功能的List
是直接的。
要實例化類型,可以使用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;
}
}
然后,要僅使用第三列初始化學生的姓名來實例化Student
,可以使用
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);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.