目录
Java 5 引入枚举类, 详情可参考 官方文档.
一言以蔽之,啥是枚举类
纯枚举值
public enum PizzaStatus {
ORDERED,
READY,
DELIVERED;
}
枚举值添加属性
public enum Distance {
KILOMETER("km", 1000),
MILE("miles", 1609.34),
METER("meters", 1),
INCH("inches", 0.0254),
CENTIMETER("cm", 0.01),
MILLIMETER("mm", 0.001);
private String unit;
private final double meters;
private Distance(String unit, double meters) {
this.unit = unit;
this.meters = meters;
}
// standard getters and setters
}
Fields, Methods and Constructors in Enums(枚举值还可以提供方法)
@Data
public class Pizza {
public enum PizzaStatus {
ORDERED(5) {
@Override
public boolean isOrdered() {
return true;
}
}, READY(2) {
@Override
public boolean isReady() {
return true;
}
}, DELIVERED(0) {
@Override
public boolean isDelivered() {
return true;
}
};
private int timeToDelivery;
PizzaStatus(int timeToDelivery) {
this.timeToDelivery = timeToDelivery;
}
// 下单
public boolean isOrdered() {
return false;
}
// 准备
public boolean isReady() {
return false;
}
// 交付
public boolean isDelivered() {
return false;
}
public int getTimeToDelivery() {
return timeToDelivery;
}
}
private PizzaStatus status;
public boolean isDeliverable() {
return this.status.isReady();
}
public void printTimeToDeliver() {
System.out.println("Time to delivery is " + this.getStatus().getTimeToDelivery());
}
}
Strategy Pattern(基于枚举值可以提供方法,这里可以拓展策略设计模式)
public enum PizzaDeliveryStrategy {
EXPRESS {
@Override
public void deliver(Pizza pz) {
System.out.println("Pizza will be delivered in express mode");
}
}, NORMAL {
@Override
public void deliver(Pizza pz) {
System.out.println("Pizza will be delivered in normal mode");
}
};
public abstract void deliver(Pizza pz);
}
public static void main(String[] args) {
Pizza testPz = new Pizza();
testPz.setStatus(Pizza.PizzaStatus.READY); // true
testPz.printTimeToDeliver(); // Time to delivery is 2
}
Custom Enum Methods(告诉我们枚举类可以在类内部使用,上文已经见到)
@Data
public class Pizza {
private PizzaStatus status;
public enum PizzaStatus {
ORDERED,
READY,
DELIVERED;
}
public boolean isDeliverable() {
if (getStatus() == PizzaStatus.READY) {
return true;
}
return false;
}
}
Using Enum Types in Switch Statements(switch+enum组合经典用法)
public int getDeliveryTimeInDays() {
switch (status) {
case ORDERED: return 5;
case READY: return 2;
case DELIVERED: return 0;
}
return 0;
}
Comparing Enum Types Using “==” Operator(枚举类比较用==
)
the “==” operator provides compile-time and run-time safety.
run-time safety
if(testPz.getStatus().equals(Pizza.PizzaStatus.DELIVERED)); ← null 会报 NullPointerException
if(testPz.getStatus() == Pizza.PizzaStatus.DELIVERED); ← Either value can be null and we won't get a NullPointerException
compile-time safety
PizzaStatus.DELIVERED.equals(PizzaStatus2.ORDERED) ← 编译不会报错,会返回false
PizzaStatus.DELIVERED == PizzaStatus2.ORDERED ← 编译会报错
如何判断一个枚举值是否存在
如何判断一个枚举值是否存在(Check if an Enum Value Exists in Java)
Singleton Pattern
public enum PizzaDeliverySystemConfiguration {
INSTANCE;
PizzaDeliverySystemConfiguration() {
// Initialization configuration which involves overriding defaults like delivery strategy
// 初始化配置,包括覆盖默认值,如交付策略
}
private PizzaDeliveryStrategy deliveryStrategy = PizzaDeliveryStrategy.NORMAL;
public static PizzaDeliverySystemConfiguration getInstance() {
return INSTANCE;
}
public PizzaDeliveryStrategy getDeliveryStrategy() {
return deliveryStrategy;
}
}
Pizza 类里追加如下方法
public void deliver() {
if (isDeliverable()) {
PizzaDeliverySystemConfiguration.getInstance().getDeliveryStrategy().deliver(this);
this.setStatus(PizzaStatus.DELIVERED);
}
}
public static void main(String[] args) {
Pizza pz = new Pizza();
pz.setStatus(Pizza.PizzaStatus.READY);
pz.deliver(); // Pizza will be delivered in normal mode
System.out.println(pz.getStatus() == Pizza.PizzaStatus.DELIVERED); // true
}
EnumSet
与HashSet相比更高效
@Data
public class Pizza {
private static EnumSet<PizzaStatus> undeliveredPizzaStatuses = EnumSet.of(PizzaStatus.ORDERED, PizzaStatus.READY);
private PizzaStatus status;
public enum PizzaStatus {
ORDERED(5) {
@Override
public boolean isOrdered() {
return true;
}
}, READY(2) {
@Override
public boolean isReady() {
return true;
}
}, DELIVERED(0) {
@Override
public boolean isDelivered() {
return true;
}
};
private int timeToDelivery;
PizzaStatus(int timeToDelivery) {
this.timeToDelivery = timeToDelivery;
}
// 下单
public boolean isOrdered() {
return false;
}
// 准备
public boolean isReady() {
return false;
}
// 交付
public boolean isDelivered() {
return false;
}
public int getTimeToDelivery() {
return timeToDelivery;
}
}
public boolean isDeliverable() {
return this.status.isReady();
}
public void printTimeToDeliver() {
System.out.println("Time to delivery is " + this.getStatus().getTimeToDelivery() + " days");
}
public static List<Pizza> getAllUndeliveredPizzas(List<Pizza> input) {
return input.stream().filter((s) -> undeliveredPizzaStatuses.contains(s.getStatus())).collect(Collectors.toList());
}
}
public static void main(String[] args) {
List<Pizza> pzList = new ArrayList<>();
Pizza pz1 = new Pizza();
pz1.setStatus(Pizza.PizzaStatus.DELIVERED);
Pizza pz2 = new Pizza();
pz2.setStatus(Pizza.PizzaStatus.ORDERED);
Pizza pz3 = new Pizza();
pz3.setStatus(Pizza.PizzaStatus.ORDERED);
Pizza pz4 = new Pizza();
pz4.setStatus(Pizza.PizzaStatus.READY);
pzList.add(pz1);
pzList.add(pz2);
pzList.add(pz3);
pzList.add(pz4);
List<Pizza> undeliveredPzs = Pizza.getAllUndeliveredPizzas(pzList);
System.out.println(undeliveredPzs.size()); // 3
}
EnumMap
EnumMap与对应的HashMap相比,它是一个高效而紧凑的实现,内部表示为数组。
EnumMap(A Guide to EnumMap)
public static EnumMap<PizzaStatus, List<Pizza>> groupPizzaByStatus(List<Pizza> pizzaList) {
EnumMap<PizzaStatus, List<Pizza>> pzByStatus = new EnumMap<PizzaStatus, List<Pizza>>(PizzaStatus.class);
for (Pizza pz : pizzaList) {
PizzaStatus status = pz.getStatus();
if (pzByStatus.containsKey(status)) {
pzByStatus.get(status).add(pz);
} else {
List<Pizza> newPzList = new ArrayList<Pizza>();
newPzList.add(pz);
pzByStatus.put(status, newPzList);
}
}
return pzByStatus;
}
Java 8 and Enums
public static List<Pizza> getAllUndeliveredPizzas(List<Pizza> input) {
return input.stream().filter((s) -> undeliveredPizzaStatuses.contains(s.getStatus())).collect(Collectors.toList());
}
public static EnumMap<PizzaStatus, List<Pizza>> groupPizzaByStatus2(List<Pizza> pzList) {
EnumMap<PizzaStatus, List<Pizza>> map = pzList.stream().filter(a -> a != null && a.getStatus() != null).collect(Collectors.groupingBy(Pizza::getStatus, () -> new EnumMap<>(PizzaStatus.class), Collectors.toList()));
return map;
}
public static Map<PizzaStatus, List<Pizza>> groupPizzaByStatus3(List<Pizza> pizzaList) {
Map<PizzaStatus, List<Pizza>> collect = pizzaList.stream().filter(a -> a != null && a.getStatus() != null).collect(Collectors.groupingBy(Pizza::getStatus));
return collect;
}
public static void main(String[] args) {
List<Pizza> pzList = new ArrayList<>();
Pizza pz1 = new Pizza();
pz1.setStatus(Pizza.PizzaStatus.DELIVERED);
Pizza pz2 = new Pizza();
pz2.setStatus(Pizza.PizzaStatus.ORDERED);
Pizza pz3 = new Pizza();
pz3.setStatus(Pizza.PizzaStatus.ORDERED);
Pizza pz4 = new Pizza();
pz4.setStatus(Pizza.PizzaStatus.READY);
pzList.add(pz1);
pzList.add(pz2);
pzList.add(pz3);
pzList.add(pz4);
EnumMap<Pizza.PizzaStatus, List<Pizza>> map = Pizza.groupPizzaByStatus(pzList);
System.out.println(map);
//{ORDERED=[Pizza(status=ORDERED), Pizza(status=ORDERED)], READY=[Pizza(status=READY)], DELIVERED=[Pizza(status=DELIVERED)]}
EnumMap<Pizza.PizzaStatus, List<Pizza>> map2 = Pizza.groupPizzaByStatus2(pzList);
System.out.println(map2);
// {ORDERED=[Pizza(status=ORDERED), Pizza(status=ORDERED)], READY=[Pizza(status=READY)], DELIVERED=[Pizza(status=DELIVERED)]}
Map<Pizza.PizzaStatus, List<Pizza>> map3 = Pizza.groupPizzaByStatus3(pzList);
System.out.println(map3);
// {READY=[Pizza(status=READY)], ORDERED=[Pizza(status=ORDERED), Pizza(status=ORDERED)], DELIVERED=[Pizza(status=DELIVERED)]}
}
JSON Representation of Enum
Further Reading:枚举类使用Jackson进行序列化与反序列化(How To Serialize and Deserialize Enums with Jackson)
@Data
public class Pizza {
private PizzaStatus status;
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum PizzaStatus {
ORDERED(5) {
@Override
public boolean isOrdered() {
return true;
}
}, READY(2) {
@Override
public boolean isReady() {
return true;
}
}, DELIVERED(0) {
@Override
public boolean isDelivered() {
return true;
}
};
private int timeToDelivery;
PizzaStatus(int timeToDelivery) {
this.timeToDelivery = timeToDelivery;
}
// 下单
public boolean isOrdered() {
return false;
}
// 准备
public boolean isReady() {
return false;
}
// 交付
public boolean isDelivered() {
return false;
}
@JsonProperty("timeToDelivery")
public int getTimeToDelivery() {
return timeToDelivery;
}
}
public boolean isDeliverable() {
return this.status.isReady();
}
}
Pizza pz = new Pizza();
pz.setStatus(Pizza.PizzaStatus.READY);
ObjectMapper objectMapper = new ObjectMapper();
String s = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(pz);
System.out.println(s);
{
"status" : {
"ready" : true,
"ordered" : false,
"delivered" : false,
"timeToDelivery" : 2
},
"deliverable" : true
}
继承在枚举类中的应用
Further Reading:继承在枚举类中的应用(Extending Enums in Java)
-----------------------------------------------------------------------------读书笔记摘自 文章:A Guide to Java Enums
-----------------------------------------------------------------------------读书笔记摘自 文章:Enum in Java
总结:
-
enum为关键字
-
枚举类不支持继承
-
Enum可以实现接口
-
枚举构造函数总是私有的。不能使用new操作符创建enum的实例
-
枚举常量是隐式 static final 的,但是它的变量仍然可以被改变。
-
我们可以在enum中定义方法,并且enum字段也可以覆盖它们。
-
我们可以在java枚举中声明抽象方法,然后所有枚举字段必须实现抽象方法
-
建议枚举使用==进行比较