我正在编写Excel导入逻辑:
public class ExcelImporter {
//...ignore constructor and other methods ...
public <R> Builder<R> sheet(String sheetName, RowConsumer<R> rowConsumer) {
return new Builder<R>(sheetName, rowConsumer);
}
public class Builder<R> {
//...ignore other method
public <F> Builder header(String name, CellConsumer<R, F> cellConsumer) {
sheetReader.header(new DefaultHeader<>(name, cellConsumer));
return this;
}
public <F> Builder header(String name, Class<F> fieldType, CellConsumer<R, String> cellConsumer) {
return header(name,cellConsumer);
}
}
}
在我的测试代码中,我收到了编译错误:
@Test
public void processSmallExcelWithConsumer() throws Exception {
try (InputStream is = getClass().getClassLoader().getResourceAsStream("工作簿1.xls")) {
ExcelImporter excelImporter = new ExcelImporter(is, "application/vnd.ms-excel")
.sheet("Sheet1", () -> new RowBean())
.header("姓名",String.class, (cell, row) -> row.setName(cell)) // no error
.header("性别",String.class, (cell, row) -> row.setSex(cell)) // "setSex" got error and `row` evaluate to `Object` ? why !?
.build();
setSex()
无法编译,且row
评估为Object
,我是如此混乱,以至于它第一次运作良好但下次失败了?
这是CellConsumer
:
@FunctionalInterface
public interface CellConsumer<R,F> {
void read(F cell,R row);
}
RowConsumer
:
@FunctionalInterface
public interface RowConsumer<R> {
R newRow();
}
错误:
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.797 s
[INFO] Finished at: 2017-07-28T23:56:26+08:00
[INFO] Final Memory: 17M/166M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.2:testCompile (default-testCompile) on project graceful-excel: Compilation failure
[ERROR] /home/terrason/workspace/maven/cnx/graceful-excel/src/test/java/cn/lenyar/excel/ExcelImporterTest.java:[81,66] 找不到符号
[ERROR] 符号: 方法 setSex(java.lang.Object)
[ERROR] 位置: 类型为java.lang.Object的变量 row
[ERROR] -> [Help 1]
请帮帮我!
答案 0 :(得分:1)
问题是您没有在标头方法中指定返回的构建器的泛型类型:
public <F> Builder header(...)
//this returns Builder which is the same as Builder<?>
//All java can infer from Builder<?> is that the generic type is an Object.
//which makes row in the second call an Object
尝试在Builder<R>
方法中返回header
:
public class ExcelImporter {
//...ignore constructor and other methods ...
public <R> Builder<R> sheet(String sheetName, RowConsumer<R> rowConsumer) {
return new Builder<R>(sheetName, rowConsumer);
}
private static class RowBean {
private String name;
private String sex;
public void setName(String name) {
this.name = name;
}
public void setSex(String sex) {
this.sex = sex;
}
}
public class Builder<R> {
public Builder(String sheetName, RowConsumer<R> rowConsumer) {
}
//...ignore other method
public <F> Builder<R> header(String name, CellConsumer<R, F> cellConsumer) {
return this;
}
public <F> Builder<R> header(String name, Class<F> fieldType, CellConsumer<R, String> cellConsumer) {
return header(name, cellConsumer);
}
public ExcelImporter build() {
return null;
}
}
@FunctionalInterface
public interface CellConsumer<R, F> {
void read(F cell, R row);
}
@FunctionalInterface
public interface RowConsumer<R> {
R newRow();
}
public static void main(String[] args) {
ExcelImporter excelImporter = new ExcelImporter()
.sheet("Sheet1", () -> new RowBean())
.header("姓名", String.class, (cell, row) -> row.setName(cell)) // no error
.header("性别", String.class, (cell, row) -> row.setSex(cell)) // no error!
.build();
}
}