You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否用Java泛型实现CSV转对象转换器?适配Cat/Dog类

CSV转实体泛型通用解决方案

问题描述

我已经实现了一个简单的CSV转换器,接收String fileName参数,能把.csv文件内容转换成List<Cat>。现在需要适配Dog类,但不允许复制现有方法只修改返回类型为List<Dog>。我试过用List<Object>作为返回类型,但后续转换成Cat或Dog时失败了,求一个基于泛型的通用解决方案。

尝试的代码

@Data
@Entity
@Table(name = "cat")
public class Cat implements Serializable {
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    @Column(columnDefinition = "int(10)", nullable = false)
    int id;

    @Column(columnDefinition = "varchar(20)", nullable = false)
    String name;    
}

@Data
@Entity
@Table(name = "dog")
public class Dog implements Serializable {
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    @Column(columnDefinition = "int(10)", nullable = false)
    int id;

    @Column(columnDefinition = "varchar(20)", nullable = false)
    String name;    
}

public List<Object> convertToObject(String fileName, String object) {
    List<Object> objList = new ArrayList();
    Path pathToFile = Paths.get(fileName);

    try (BufferedReader br = Files.newBufferedReader(pathToFile)) {
        int index = 1;

        // 读取文件第一行(表头)
        String line = br.readLine();

        // 循环读取所有数据行
        while (line != null) {

            if (index > 1) {
                switch (object) {
                    case "cat" : {
                        // 按逗号拆分每行数据
                        String[] attributes = line.split(",");

                        Cat cat = new Cat();
                        createCat(attributes, cat);
                        objList.add(cat);   
                    }

                    case "dog" : {
                        // 按逗号拆分每行数据
                        String[] attributes = line.split(",");

                        Dog dog = new Dog();
                        createDog(attributes, dog);
                        objList.add(dog);   
                    }
                }
            }

            // 读取下一行
            line = br.readLine();
            index++;
        }

    } catch (IOException ex) {
        ex.printStackTrace(System.out);
    }

    return objList;
}

泛型解决方案

1. 定义通用映射接口

创建一个统一接口,规范CSV属性到实体的映射逻辑,让Cat和Dog实现该接口:

public interface CsvMappable {
    // 将CSV拆分后的属性数组映射到实体字段
    void mapFromCsv(String[] attributes);
}

修改Cat和Dog实现接口,把原来的createCat、createDog逻辑迁移到接口方法中:

@Data
@Entity
@Table(name = "cat")
public class Cat implements Serializable, CsvMappable {
    // 原有字段保持不变

    @Override
    public void mapFromCsv(String[] attributes) {
        this.id = Integer.parseInt(attributes[0]);
        this.name = attributes[1];
        // 可根据实际CSV列顺序调整逻辑
    }
}

@Data
@Entity
@Table(name = "dog")
public class Dog implements Serializable, CsvMappable {
    // 原有字段保持不变

    @Override
    public void mapFromCsv(String[] attributes) {
        this.id = Integer.parseInt(attributes[0]);
        this.name = attributes[1];
        // 可根据实际CSV列顺序调整逻辑
    }
}

2. 改造为泛型转换器方法

替换原有的convertToObject方法,通过泛型约束实现通用转换,彻底避免重复代码:

import java.lang.reflect.InvocationTargetException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.io.BufferedReader;
import java.io.IOException;

public <T extends CsvMappable> List<T> convertToEntityList(String fileName, Class<T> entityClass) {
    List<T> entityList = new ArrayList<>();
    Path pathToFile = Paths.get(fileName);

    try (BufferedReader br = Files.newBufferedReader(pathToFile)) {
        String line = br.readLine(); // 跳过表头行
        // 循环读取数据行
        while ((line = br.readLine()) != null) {
            String[] attributes = line.split(",");
            // 通过反射创建实体实例
            T entity = entityClass.getDeclaredConstructor().newInstance();
            // 调用映射方法填充字段
            entity.mapFromCsv(attributes);
            entityList.add(entity);
        }
    } catch (IOException | InstantiationException | IllegalAccessException 
             | NoSuchMethodException | InvocationTargetException ex) {
        ex.printStackTrace();
    }

    return entityList;
}

3. 调用方式

直接指定目标实体类,即可获取类型安全的列表:

// 转换为Cat列表
List<Cat> catList = convertToEntityList("cats.csv", Cat.class);
// 转换为Dog列表
List<Dog> dogList = convertToEntityList("dogs.csv", Dog.class);

可选优化:避免反射

如果不想使用反射,可以传入Supplier<T>来创建实体实例,减少异常处理和性能开销:

public <T extends CsvMappable> List<T> convertToEntityList(String fileName, Supplier<T> entitySupplier) {
    List<T> entityList = new ArrayList<>();
    Path pathToFile = Paths.get(fileName);

    try (BufferedReader br = Files.newBufferedReader(pathToFile)) {
        String line = br.readLine();
        while ((line = br.readLine()) != null) {
            String[] attributes = line.split(",");
            T entity = entitySupplier.get();
            entity.mapFromCsv(attributes);
            entityList.add(entity);
        }
    } catch (IOException ex) {
        ex.printStackTrace();
    }

    return entityList;
}

调用时使用方法引用:

List<Cat> catList = convertToEntityList("cats.csv", Cat::new);
List<Dog> dogList = convertToEntityList("dogs.csv", Dog::new);

内容的提问来源于stack exchange,提问作者dbuergi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 15:31:11