簡體   English   中英

實現通用解析器類

[英]Impelement a generic parser class

我想編寫一個通用的excel解析器類。 但是將函數傳遞給它有一個問題。

解析器讀取excel行並從每行創建一個對象。 通過系統視圖,它將獲得一個excel文件,一個類以及每個列與一個對象字段(其setter函數)之間的映射,並生成一個對象列表。

如果我們為每個pojo創建一個ParserStudent 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類,我有兩個問題:

  1. 如何將類和設置方法傳遞給解析器類?
  2. 如何新建一個泛型類(調用其構造函數)並使用提到的setter設置其字段?

您傳遞的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>

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM