首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >元素--泛型解析器类

元素--泛型解析器类
EN

Stack Overflow用户
提问于 2017-10-19 05:52:28
回答 2查看 1K关注 0票数 2

我想编写一个通用的excel解析器类。但是将函数传递给它是有问题的。

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

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

代码语言:javascript
运行
复制
private Map<Integer, java.util.function.Consumer> mapColumnIndexToSetter = new HashMap<>();
mapColumnIndexToSetter .put(3, Student::setName);

但是Student::setName得到了一个错误:

代码语言:javascript
运行
复制
Error:(30, 41) java: incompatible types: invalid method reference
incompatible types: java.lang.Object cannot be converted to java.lang.String`

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

关于这个泛型Parser类在java 8中的实现,我有两个问题:

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

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-10-19 09:11:11

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

顺便说一句,excel表的列很少如此稀疏,以至于它们证明了从索引到函数使用HashMap是正确的。每个列都有一个函数的List是直进的.

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

如果把它组合在一起,这样的类可能看起来就像

代码语言:javascript
运行
复制
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的名称,只需使用第三列来初始化它们的名称,可以使用

代码语言:javascript
运行
复制
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);
票数 2
EN

Stack Overflow用户

发布于 2017-10-19 06:07:41

要传递的FunctionMap's声明不兼容。

Map声明中,您忽略了为Function指定泛型类型参数,因此将按以下方式推断这些参数:

代码语言:javascript
运行
复制
Function<Object, Object>

另一方面,你要通过:

代码语言:javascript
运行
复制
// I guess getName() is returning a String
Function<Student, String> function = Student::getName;

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

代码语言:javascript
运行
复制
Function<? extends Object, ? extends Object>

而且,只要您能够从Object调用中获得Functionextends Object显然是没有意义的,因此可以简化为:

代码语言:javascript
运行
复制
Function<?, ?>

但是,您最好在这里添加一个泛型限制,例如:

代码语言:javascript
运行
复制
Function<?, ? extends Serializable>
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46823514

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档