首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 泛型與反射實作通用 CSV 匯出工具

     編輯:Java 相關知識

需求背景

專案中常需將不同實體類別的集合匯出為 CSV 檔案。若為每個類別寫死匯出邏輯,程式碼冗餘且難維護。利用 Java 泛型與反射,可實作一個通用方法,自動根據物件屬性動態生成標題列與資料列,大幅簡化開發工作量。

核心實作

import java.io.*;
import java.lang.reflect.Field;
import java.util.List;
import org.apache.commons.lang3.StringUtils;

public class CsvExporter {

    /**
     * 將任意物件列表匯出為 CSV
     * @param list  資料列表,不可為 null 或空
     * @param outFile 輸出檔案完整路徑
     * @throws IOException IO 異常
     * @throws IllegalArgumentException 路徑為空
     */
    public static  void exportToCsv(List list, String outFile) throws IOException {
        if (list == null || list.isEmpty()) {
            return; // 無資料不生成檔案
        }
        if (StringUtils.isEmpty(outFile)) {
            throw new IllegalArgumentException("輸出檔案路徑不可為空");
        }

        boolean isFirst = true;
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(outFile))) {
            for (T obj : list) {
                StringBuilder headerSb = new StringBuilder();
                StringBuilder dataSb = new StringBuilder();

                Class clazz = obj.getClass();
                Field[] fields = clazz.getDeclaredFields();

                for (Field field : fields) {
                    field.setAccessible(true); // 允許存取 private 欄位
                    try {
                        if (isFirst) {
                            headerSb.append(field.getName()).append(',');
                        }
                        Object value = field.get(obj);
                        dataSb.append(value != null ? value.toString() : "").append(',');
                    } catch (IllegalAccessException e) {
                        // 理論上不會發生,因已 setAccessible(true)
                        e.printStackTrace();
                    }
                }

                if (isFirst) {
                    writer.write(headerSb.toString());
                    writer.newLine();
                    isFirst = false;
                }
                writer.write(dataSb.toString());
                writer.newLine();
            }
        }
    }
}

關鍵技術點解析

  1. 泛型 <T>:方法接受任意類型列表,編譯期型別安全,呼叫端無需強制轉型。
  2. 反射 Field[] getDeclaredFields():取得類別宣告的所有欄位(含 private),不包含繼承自父類的欄位。若需包含父類欄位,可遞迴遍歷 getSuperclass()。
  3. field.setAccessible(true):繞過 Java 存取修飾符檢查,直接讀取私有欄位值。
  4. 動態標題列生成:首筆資料迴圈時同步建立 CSV 標題,確保欄位順序與資料一致。
  5. 資源管理:採用 try-with-resources 自動關閉 BufferedWriter,確保檔案正確落盤。
  6. 空值處理:欄位值為 null 時輸出空字串,避免 NullPointerException。

使用範例

// 實體類別
public class User {
    private Long id;
    private String username;
    private String email;
    private Integer age;
    // getter/setter 省略
}

// 呼叫匯出
List users = userService.findAll();
CsvExporter.exportToCsv(users, "D:/export/users.csv");

進階擴充建議

  • 註解驅動欄位順序/名稱:自訂 @CsvColumn(order = 1, name = "使用者ID"),透過反射讀取註解控制輸出順序與中文標題。
  • 日期/數值格式化:針對 Date、BigDecimal 等類型套用 SimpleDateFormat 或 DecimalFormat。
  • 大資料量分批寫入:搭配 ScrollableResultSet 或分頁查詢,避免一次載入所有資料導致 OOM。
  • 支援巢狀物件/集合:遞迴展開關聯物件欄位,或以 JSON 字串序列化複雜類型。
  • 編碼指定:建構 FileWriter 時指定 StandardCharsets.UTF_8(或加 BOM 的 UTF-8)相容 Excel 開啟。

常見問題與解決

問題原因解決方案
CSV 開啟中文亂碼Excel 預設用系統編碼(如 Big5)讀取 UTF-8 檔輸出 UTF-8 with BOM,或使用 Excel「資料→從文字/CSV」匯入指定編碼
欄位包含逗號/換行導致欄位錯位未處理 CSV 特殊字元值包含逗號、雙引號、換行時,以雙引號包裹並將內部雙引號轉義為兩個雙引號
父類別欄位未匯出getDeclaredFields() 僅取得當前類別欄位遞迴遍歷 clazz.getSuperclass() 直到 Object.class
靜態欄位被匯出未過濾 Modifier.isStatic(field.getModifiers())在迴圈中判斷並跳過 static/final/transient 欄位

結語

以泛型與反射實作通用 CSV 匯出,是 Java 後端開發中極具性價比的工具化實踐。配合註解擴充與異常處理,即可滿足企業級報表匯出的大多數需求,建議封裝為專案共用工具模組持續演進。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved