用于静态值的Java Enum或HashMap

时间:2015-07-17 10:21:10

标签: java enums

我正在生成一个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能为我带来什么。

对于每种方法,有什么理由支持/反对,这是一个特殊情况,其中一个是优越的,还是一种优越的方式?

4 个答案:

答案 0 :(得分:7)

我总是在enum使用enum,因为Map有先天的排序,而enum则没有。{/ p>

通过使用enum,您可以从枚举本身生成CTL文件,并使用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)); } 值作为工厂来填充csv文件。

String path = Environment.getExternalStorageDirectory().getPath();

String selection = MediaStore.Audio.Media.IS_MUSIC + " !=" + 0
        + " AND " + MediaStore.Audio.Media.DATA + " LIKE '" + path
        + "/YourFolderNameHere/%'";

答案 1 :(得分:2)

我更喜欢Enum - 使用类型将为您提供扩展和更改实现的灵活性,使用抽象并仍然将其封装在您的类中。要使用示例,如果您稍后决定要为CTL文件格式化日期,该怎么办?使用枚举,您可以使用抽象实现,重要的是,当您有十个日期和一百列时:

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会让它更快。

答案 2 :(得分:1)

在设计应用程序时,您始终会考虑将来可能发生的变化。您的列的顺序可能会更改,或者您将获得更多列。使用Map时您获得的主要内容(您还应该编程到Map界面,而不是HashMap)是能够在应用程序之外轻松存储此配置。

将配置与应用程序逻辑分离可能非常有用,即使您此时没有计划,也可能希望在将来某个时候执行此操作。

使用枚举可以让你对代码进行更多的静态控制,这样可以更容易避免错误(但你应该编写测试)。

总结:

地图的积极因素:

  • 易于更改配置
  • 配置可以存储在系统外部
  • 更容易扩展
  • 可以为此任务编写通用代码/框架

地图的否定:

  • 稍微容易犯错误

Enum的积极因素:

  • 更容易不做msitakes,静态检查

Enum的否定:

  • 您在complie time修复配置
  • 更难扩展

对于Map解决方案,我实际上推荐使用SortedMap接口而不是HashMap,其中TreeMap是实际的实现。如果订单很重要。

答案 3 :(得分:1)

我会创建一个包含列名属性的类,如:

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

  // getters and setters here.
}

其中id和name是csv文件中的实际列。

然后创建记录列表List<CSVRecord> csvRecordList