能否用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
相关产品推荐
相关产品推荐

