簡體   English   中英

用於靜態值的Java Enum或HashMap

[英]Java Enum or HashMap for static values

我正在生成一個CSV文件和CTL文件,以便與sqlldr一起使用。 CTL文件需要知道我要加載的列的名稱,我的CSV文件需要知道這些字段的默認值。

/*
 * Models a line in the CSV file
 */
public class CSVRecord {
  ...
}

/*
 * Models the CTL file
 */
public class ControlFile {
    ...
}

這兩個類初始化並在CSVExportFile ,我有兩種方法:

1.枚舉

public enum Columns {
    ID("1"),
    NAME("Bob"),
    ...
}

2. HashMap

public class CSVExportFile {
    private HashMap<String, String> columns;

    public CSVExportFile() {
        columns = new HashMap<String, String>();
        columns.put("ID", "1");
        columns.put("Name", "Bob");
        ...
    }
}

HashMap減少了列的范圍,並且意味着它們只能在CSVExportFile 我不打算擴展這個功能(所有類都將是final ),所以我不確定我的enum我帶來什么。

對於每種方法有什么爭論,這是一個特殊情況,其中一個是優越的,還是一種優越的方式?

我總是會在這里使用enum ,因為enum有一個與生俱來的排序,而Map則沒有。

通過使用enum您可以從枚舉本身生成CTL文件,並使用enum值作為工廠來填充csv文件。

class MyObj {

    final String foreName;
    final String surname;

    public MyObj(String foreName, String surname) {
        this.foreName = foreName;
        this.surname = surname;
    }

    public String getForeName() {
        return foreName;
    }

    public String getSurname() {
        return surname;
    }

}

enum Column {

    Forename {

                @Override
                String fromMyObj(MyObj it) {
                    return it.getForeName();
                }
            },
    Surname {

                @Override
                String fromMyObj(MyObj it) {
                    return it.getSurname();
                }
            },;

    abstract String fromMyObj(MyObj it);

    static String asSelectStatement(Set<Column> columns, String tableName) {
        return join(columns, ",", "SELECT ", " FROM " + tableName);
    }

    static String asCSVHeader(Set<Column> columns) {
        return join(columns, ",");
    }

    static String asCSV(Set<Column> columns, MyObj it) {
        return join(columns, (Column a) -> a.fromMyObj(it), ",");
    }

    private static String join(Set<Column> columns, String between) {
        return join(columns, new StringJoiner(between));
    }

    private static String join(Set<Column> columns, String between, String prefix, String suffix) {
        return join(columns, new StringJoiner(between, prefix, suffix));
    }

    private static String join(Set<Column> columns, StringJoiner joined) {
        return join(columns, (Column a) -> a.name(), joined);
    }

    private static String join(Set<Column> columns, Function<Column, String> as, String between) {
        return join(columns, as, new StringJoiner(between));
    }

    private static String join(Set<Column> columns, Function<Column, String> as, String between, String prefix, String suffix) {
        return join(columns, as, new StringJoiner(between, prefix, suffix));
    }

    private static String join(Set<Column> columns, Function<Column, String> as, StringJoiner joined) {
        for (Column c : columns) {
            joined.add(as.apply(c));
        }
        return joined.toString();
    }

    // Also simple to auto-populate prepared statements, build INSERT statements etc.
}

public void test() {
    Set<Column> columns = EnumSet.of(Column.Forename, Column.Surname);
    System.out.println("As Select: " + Column.asSelectStatement(columns, "MyTable"));
    System.out.println("As CSV Header: " + Column.asCSVHeader(columns));
    MyObj it = new MyObj("My Forename", "My Surname");
    System.out.println("As CSV: " + Column.asCSV(columns, it));
}

我更喜歡Enum - 使用類型將為您提供擴展和更改實現的靈活性,使用抽象並仍然將其封裝在您的類中。 要使用示例,如果您稍后決定要為CTL文件格式化日期,該怎么辦? 使用enum,您可以使用抽象實現,重要的是,當您有十個日期和一百列時:

public enum Column {
    ID("1"),
    NAME("Bob"),
    DATE_OF_BIRTH("1980-01-01", "yyyy-MM-dd", "yyyyMMdd");
    private String defaultValue;
    private String ctlDefaultValue;

    Column(String defaultValue) {
        this.defaultValue = defaultValue;
    }

    Column(String defaultValue, String csvFormat, String ctlFormat) {
        this(defaultValue);
        try {
            this.ctlDefaultValue = new SimpleDateFormat(ctlFormat)
                .format(new SimpleDateFormat(csvFormat)
                .parseObject(defaultValue));
        } catch (ParseException e) {
            this.ctlDefaultValue = "";
        }
    }

    public String valueForCTL() {
        return ctlDefaultValue == null ? defaultValue : ctlDefaultValue;
    }

    public String valueForCsv() {
        return defaultValue;
    }

    public static void main(String[] args) {
        System.out.println(DATE_OF_BIRTH.valueForCTL());
        System.out.println(DATE_OF_BIRTH.valueForCsv());
    }
}

您可能還希望出於某種原因存儲一種值,然后您只需要為枚舉添加新屬性。 使用地圖方法,您實際上需要第二個地圖或定義要用作地圖值的類型。

如果你發現,你需要不同的CSV和CTL訂單怎么辦? 好吧,使用Map(Sorted one),創建一個不同排序的副本應該很容易,但你可以輕松地使用enum:

public enum ColumnDifferentOrder{
    ID("1", 3),
    NAME("Bob", 2),
    DATE_OF_BIRTH("1980-01-01", 1);

    private String defaultValue;
    private int csvOrder;

    ColumnDifferentOrder(String defaultValue, int csvOrder) {
        this.defaultValue = defaultValue;
        this.csvOrder = csvOrder;
    }

    public static ColumnDifferentOrder[] orderForCsv() {
        ColumnDifferentOrder[] columns  = ColumnDifferentOrder.values();
        Arrays.sort(columns, new Comparator<ColumnDifferentOrder>() {
            @Override
            public int compare(ColumnDifferentOrder o1, ColumnDifferentOrder o2) {
                return o1.csvOrder - o2.csvOrder;
            }
        });
        return columns;
    }

    public static ColumnDifferentOrder[] orderForCtl() {
        return ColumnDifferentOrder.values();
    }


    public static void main(String[] args) {
        System.out.println(Arrays.toString(ColumnDifferentOrder.orderForCsv()));
        System.out.println(Arrays.toString(ColumnDifferentOrder.orderForCtl()));

    }
}

我唯一可以想到的是,Map會更好,就是當你實際上不想迭代,但訪問所選值時 - Map會更快。

在設計應用程序時,您始終會考慮將來可能發生的變化。 您的列的順序可能會更改,或者您將獲得更多列。 使用Map時獲得的主要內容(您還應該編程到Map接口而不是HashMap )是在應用程序之外輕松存儲此配置的功能。

將配置與應用程序邏輯分離可能非常有用,即使您此時沒有計划,也可能希望在將來的某個時候執行此操作。

使用枚舉可以讓您對代碼進行更多的靜態控制,這樣可以更容易避免錯誤(但無論如何都應該編寫測試)。

綜上所述:

地圖的積極因素:

  • 易於更改配置
  • 配置可以存儲在系統外部
  • 更容易擴展
  • 可以為此任務編寫通用代碼/框架

地圖的負面影響:

  • 稍微容易犯錯誤

Enum的積極因素:

  • 更容易不做msitakes,靜態檢查

Enum的否定:

  • 您在complie時修復配置
  • 更難延伸

對於Map解決方案,我實際上推薦使用SortedMap接口而不是HashMap,而TreeMap是實際的實現。 如果訂單很重要。

我將創建一個具有列名屬性的類,如:

public class CSVRecord {
  private int id;
  private String name;

  // getters and setters here.
}

其中id和name是csv文件中的實際列。

然后創建記錄List<CSVRecord> csvRecordList

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM