Kid*_*rla 9 java enums idiomatic
我似乎多次遇到这个问题,我想问社区我是不是只是在咆哮错误的树.基本上我的问题可以归结为:如果我有一个值很重要的枚举(在Java中),我应该使用枚举还是有更好的方法,如果我使用枚举那么什么是反向查找的最佳方法吗?
这是一个例子.假设我想创建一个代表特定月份和年份的bean.我可能会创建如下内容:
public interface MonthAndYear {
Month getMonth();
void setMonth(Month month);
int getYear();
void setYear(int year);
}
Run Code Online (Sandbox Code Playgroud)
在这里,我将我的月份存储为一个名为Month的单独类,因此它是类型安全的.如果我只是输入int,那么任何人都可以传入13或5,643或-100作为数字,并且在编译时无法检查它.我限制他们把一个月我将实现为枚举:
public enum Month {
JANUARY,
FEBRUARY,
MARCH,
APRIL,
MAY,
JUNE,
JULY,
AUGUST,
SEPTEMBER,
OCTOBER,
NOVEMBER,
DECEMBER;
}
Run Code Online (Sandbox Code Playgroud)
现在假设我有一些我想写的后端数据库,它只接受整数形式.那么标准的方法似乎是:
public enum Month {
JANUARY(1),
FEBRUARY(2),
MARCH(3),
APRIL(4),
MAY(5),
JUNE(6),
JULY(7),
AUGUST(8),
SEPTEMBER(9),
OCTOBER(10),
NOVEMBER(11),
DECEMBER(12);
private int monthNum;
public Month(int monthNum) {
this.monthNum = monthNum;
}
public getMonthNum() {
return monthNum;
}
}
Run Code Online (Sandbox Code Playgroud)
相当简单,但如果我想从数据库中读取这些值并编写它们会发生什么?我可以使用枚举中的case语句实现一个静态函数,它接受一个int并返回相应的Month对象.但这意味着如果我改变了什么,那么我将不得不改变这个函数以及构造函数参数 - 在两个地方改变.所以这就是我一直在做的事情.首先,我创建了一个可逆的地图类,如下所示:
public class ReversibleHashMap<K,V> extends java.util.HashMap<K,V> {
private java.util.HashMap<V,K> reverseMap;
public ReversibleHashMap() {
super();
reverseMap = new java.util.HashMap<V,K>();
}
@Override
public V put(K k, V v) {
reverseMap.put(v, k);
return super.put(k,v);
}
public K reverseGet(V v) {
return reverseMap.get(v);
}
}
Run Code Online (Sandbox Code Playgroud)
然后我在我的枚举中实现了这个而不是构造函数方法:
public enum Month {
JANUARY,
FEBRUARY,
MARCH,
APRIL,
MAY,
JUNE,
JULY,
AUGUST,
SEPTEMBER,
OCTOBER,
NOVEMBER,
DECEMBER;
private static ReversibleHashMap<java.lang.Integer,Month> monthNumMap;
static {
monthNumMap = new ReversibleHashMap<java.lang.Integer,Month>();
monthNumMap.put(new java.lang.Integer(1),JANUARY);
monthNumMap.put(new java.lang.Integer(2),FEBRUARY);
monthNumMap.put(new java.lang.Integer(3),MARCH);
monthNumMap.put(new java.lang.Integer(4),APRIL);
monthNumMap.put(new java.lang.Integer(5),MAY);
monthNumMap.put(new java.lang.Integer(6),JUNE);
monthNumMap.put(new java.lang.Integer(7),JULY);
monthNumMap.put(new java.lang.Integer(8),AUGUST);
monthNumMap.put(new java.lang.Integer(9),SEPTEMBER);
monthNumMap.put(new java.lang.Integer(10),OCTOBER);
monthNumMap.put(new java.lang.Integer(11),NOVEMBER);
monthNumMap.put(new java.lang.Integer(12),DECEMBER);
}
public int getMonthNum() {
return monthNumMap.reverseGet(this);
}
public static Month fromInt(int monthNum) {
return monthNumMap.get(new java.lang.Integer(monthNum));
}
}
Run Code Online (Sandbox Code Playgroud)
现在这可以做我想要的一切,但它看起来仍然是错误的.人们向我建议"如果枚举具有有意义的内部值,则应该使用常量".但是,我不知道这种方法将如何给我提供我正在寻找的类型安全性.我开发的方式确实看起来过于复杂.有没有一些标准的方法来做这种事情?
PS:我知道政府增加一个月的可能性......相当不太可能,但想想更大的情况 - 对于枚举有很多用途.
Jon*_*eet 11
这是一种非常常见的模式,它对于枚举很好......但它可以更简单地实现.有没有需要"可逆映射" -这需要在构造函数中的月份数是从去更好的版本Month来int.但走另一条路也不是太难:
public enum Month {
JANUARY(1),
FEBRUARY(2),
MARCH(3),
APRIL(4),
MAY(5),
JUNE(6),
JULY(7),
AUGUST(8),
SEPTEMBER(9),
OCTOBER(10),
NOVEMBER(11),
DECEMBER(12);
private static final Map<Integer, Month> numberToMonthMap;
private final int monthNum;
static {
numberToMonthMap = new HashMap<Integer, Month>();
for (Month month : EnumSet.allOf(Month.class)) {
numberToMonthMap.put(month.getMonthNum(), month);
}
}
private Month(int monthNum) {
this.monthNum = monthNum;
}
public int getMonthNum() {
return monthNum;
}
public static Month fromMonthNum(int value) {
Month ret = numberToMonthMap.get(value);
if (ret == null) {
throw new IllegalArgumentException(); // Or just return null
}
return ret;
}
}
Run Code Online (Sandbox Code Playgroud)
在您知道从1到N的数字的特定情况下,您可以简单地使用数组 - 获取Month.values()[value - 1]或缓存返回值Month.values()以防止在每次调用时创建新数组.(正如克莱图斯所说,getMonthNum可以回来ordinal() + 1.)
但是,值得在更一般的情况下意识到上述模式,其中值可能是乱序的,或者是稀疏分布的.
重要的是要注意在创建所有枚举值之后执行静态初始化程序.写作会很好
numberToMonthMap.put(monthNum, this);
Run Code Online (Sandbox Code Playgroud)
在构造函数中添加一个静态变量初始化器numberToMonthMap,但是这不起作用 - 你会NullReferenceException立即得到一个,因为你试图将值放入一个尚不存在的地图中:(
| 归档时间: |
|
| 查看次数: |
1469 次 |
| 最近记录: |