枚举可以做什么
假设我们现在想表达星期,为了避免魔法值的出现,我们可能会写一个常量类:
package com.tea.modules.java8.enums;
/**
* com.tea.modules.java8.enums <br>
* 使用抽象类来表达常量,防止被篡改
* @author jaymin
* @since 2021/6/9
*/
public abstract class WeekConstant {
/**
* 周一
*/
public static final Integer MON = 1;
/**
* 周二
*/
public static final Integer TUE = 2;
/**
* 周三
*/
public static final Integer WEB = 3;
/**
* 周四
*/
public static final Integer THUR = 4;
/**
* 周五
*/
public static final Integer FRI = 5;
/**
* 周六
*/
public static final Integer SAT = 6;
/**
* 周日
*/
public static final Integer SUN = 7;
}
这样一来,1-7的星期数就可以用WeekConstant.MON
这样的方式来表达了,好看了不少,但是仍然存在一定的缺陷。
假设我们现在往WeekConstant
中再添加一行:
public static final Integer WEEK = 1;
将其传入到一个接收参数为”星期一”的方法中,并不会产生任何问题,因为都能表示1,但是从代码阅读上来看,出现歧义了。
JDK提供了Enum
枚举类,让代码可读性更强,同时它也是类型安全的类,所有的枚举类都被final
修饰,还可以很好地实现单例模式.
枚举类基础用法
定义一个枚举类
- Week
package com.tea.modules.java8.enums;
/**
* com.tea.modules.java8.enums <br>
* 使用枚举类来表示星期
*
* @author jaymin
* @since 2021/6/9
*/
public enum WeekEnum {
/**
* 周一
*/
MON,
/**
* 周二
*/
TUE,
/**
* 周三
*/
WEB,
/**
* 周四
*/
THUR,
/**
* 周五
*/
FRI,
/**
* 周六
*/
SAT,
/**
* 周日
*/
SUN;
}
- Demo
package com.tea.modules.java8.enums;
/**
* com.tea.modules.java8.enums <br>
* 实战枚举类
*
* @author jaymin
* @since 2021/6/9
*/
public class EnumDemo {
/**
* 了解枚举的基本功能
*/
private static void enumFunction() {
// 获取所有的枚举信息
WeekEnum[] weekDays = WeekEnum.values();
for (WeekEnum weekDay : weekDays) {
String enumName = "当前枚举名称:" + weekDay.name();
String enumIndex = " 枚举位置:" + weekDay.ordinal();
String enumClass = " 枚举类型:" + weekDay.getDeclaringClass();
System.out.println(enumName + enumIndex + enumClass);
}
WeekEnum mon = WeekEnum.valueOf("MON");
System.out.println(mon.name());
WeekEnum monB = Enum.valueOf(WeekEnum.class, "MON");
System.out.println(monB);
}
public static void main(String[] args) {
enumFunction();
}
}
输出结果:
当前枚举名称:MON 枚举位置:0 枚举类型:class com.tea.modules.java8.enums.WeekEnum
当前枚举名称:TUE 枚举位置:1 枚举类型:class com.tea.modules.java8.enums.WeekEnum
当前枚举名称:WEB 枚举位置:2 枚举类型:class com.tea.modules.java8.enums.WeekEnum
当前枚举名称:THUR 枚举位置:3 枚举类型:class com.tea.modules.java8.enums.WeekEnum
当前枚举名称:FRI 枚举位置:4 枚举类型:class com.tea.modules.java8.enums.WeekEnum
当前枚举名称:SAT 枚举位置:5 枚举类型:class com.tea.modules.java8.enums.WeekEnum
当前枚举名称:SUN 枚举位置:6 枚举类型:class com.tea.modules.java8.enums.WeekEnum
MON
MON
API Document
API |
描述 |
---|---|
name |
枚举的名字 |
Enum.values() |
返回一个当前枚举类中的所有枚举元素 |
ordinal |
返回当前枚举在枚举类中的索引,从0开始 |
getDeclaringClass |
返回枚举类的类型 |
Enum.valueOf() |
返回与传入的名称相等的枚举,可能会抛出异常 |
switch配合枚举类编写状态机
OK,现在我们将需求变动一下:
周一到周五是工作日,输出工作时间;undefined 周六周日是休息日,输出“休息”;
/**
* 输入工作日,输出工作时间 <br>
* 枚举的本质就是int,配合switch的时候,编译会做类似于ordinal来确定int值
*/
private static void printWorkDays(WeekEnum weekEnum) {
switch (weekEnum) {
case MON:
System.out.println("今天是工作日-8:30-5:30");
break;
case TUE:
System.out.println("今天是工作日-8:30-5:30");
break;
case WEB:
System.out.println("今天是工作日-8:30-5:30");
break;
case THUR:
System.out.println("今天是工作日-8:30-5:30");
break;
case FRI:
System.out.println("今天是工作日-8:30-5:30");
break;
default:
System.out.println("休息");
}
}
可读性得到了提高,如果你看到代码里面有人写:
case 1
这种代码,请提醒他可以使用枚举增加可读性.
使用抽象方法为每个枚举指定特定的行为
枚举不仅可以用来表示常量,有些时候,我们也可以将一些简单的计算逻辑写在枚举类中。这个时候,可以使用抽象方法
来定义每个枚举需要实现的行为.
package com.tea.modules.java8.enums;
import lombok.Getter;
/**
* com.tea.modules.java8.enums <br>
* 运算符枚举
*
* @author jaymin
* @since 2021/6/10
*/
@Getter
public enum OperationEnum {
/**
* 加
*/
PLUS("+") {
@Override
public double apply(double x, double y) {
return x + y;
}
},
/**
* 减
*/
MINUS("-") {
@Override
public double apply(double x, double y) {
return x - y;
}
},
/**
* 乘
*/
TIMES("*") {
@Override
public double apply(double x, double y) {
return x * y;
}
},
/**
* 除
*/
DIVIDE("/") {
@Override
public double apply(double x, double y) {
return x / y;
}
};
/**
* 运算符
*/
private final String symbol;
OperationEnum(String symbol) {
this.symbol = symbol;
}
public abstract double apply(double x, double y);
}
接口与枚举类
枚举类是final类,不支持继承关系。这个可以从反编译的文件中查看:
反编译
可以通过接口来让枚举实现一些通用的方法
- 定义一个接口,声明打印名字的能力
package com.tea.modules.java8.enums;
/**
* com.tea.modules.java8.enums
* 枚举接口
* @author jaymin
* @since 2021/6/17
*/
public interface EnumInfoService {
/**
* 打印枚举的名字
*/
void printName();
}
- 枚举类实现接口
package com.tea.modules.java8.enums;
/**
* com.tea.modules.java8.enums <br>
* 使用枚举类来表示星期
*
* @author jaymin
* @since 2021/6/9
*/
public enum WeekEnum implements EnumInfoService{
/**
* 周一
*/
MON,
/**
* 周二
*/
TUE,
/**
* 周三
*/
WEB,
/**
* 周四
*/
THUR,
/**
* 周五
*/
FRI,
/**
* 周六
*/
SAT,
/**
* 周日
*/
SUN;
@Override
public void printName() {
System.out.println(this.name());
}
}
- Demo
/**
* 枚举与接口
*/
private static void printEnumInfo(){
EnumInfoService web = WeekEnum.WEB;
web.printName();
}
public static void main(String[] args) {
printEnumInfo();
}
- Result
WEB
EnumSet
EnumSet可以存储一个枚举中的元素,它提供了一种以集合的方式去操作枚举类的途径。
- enumSet
/**
* EnumSet 的设计充分考虑到了速度因素,因为它必须与非常高效的 bit 标志相竞争(其操作与 HashSet 相比,非常地快).<br>
* 就其内部而言,它(可能)就是将一个 long 值作为比特向量,所以 EnumSet 非常快速高效。<br>
* 使用 EnumSet 的优点是,它在说明一个二进制位是否存在时,具有更好的表达能力,并且无需担心性能。
*/
private static void enumSet() {
// 空构造器
EnumSet<WeekEnum> weekEnums = EnumSet.noneOf(WeekEnum.class);
weekEnums.add(WeekEnum.MON);
weekEnums.add(WeekEnum.TUE);
weekEnums.add(WeekEnum.WEB);
// of工厂,可以接收多个enum
weekEnums.addAll(EnumSet.of(WeekEnum.THUR, WeekEnum.FRI, WeekEnum.SAT, WeekEnum.SUN));
System.out.println(weekEnums);
// range-范围
weekEnums.removeAll(EnumSet.range(WeekEnum.MON, WeekEnum.WEB));
System.out.println(weekEnums);
// 创建一个与指定枚举集具有相同元素类型的枚举集,最初包含指定集中未包含的所有此类型的元素。
weekEnums = EnumSet.complementOf(weekEnums);
System.out.println(weekEnums);
}
- Result
[MON, TUE, WEB, THUR, FRI, SAT, SUN]
[THUR, FRI, SAT, SUN]
[MON, TUE, WEB]
EnumMap
EnumMap可以以枚举作为Key,提供一种更快的速度来访问Map.
- enumMap
/**
* EnumMap 是一种特殊的 Map,它要求其中的键(key)必须来自一个 enum,<br>
* 由于 enum 本身的限制,所以 EnumMap 在内部可由数组实现。<br>
* 因此 EnumMap 的速度很快,我们可以放心地使用 enum 实例在 EnumMap 中进行查找操作。<br>
* 不过,我们只能将 enum 的实例作为键来调用 put() 可方法,其他操作与使用一般的 Map 差不多。<br>
* 这里我们的例子是使用EnumMap来实现一个简单的命令模式
*/
private static void enumMap() {
EnumMap<WeekEnum, CommandService> commandServiceEnumMap = new EnumMap<>(WeekEnum.class);
commandServiceEnumMap.put(WeekEnum.MON, () -> System.out.println("周一白酒涨停"));
commandServiceEnumMap.put(WeekEnum.TUE, () -> System.out.println("周二有色跌停"));
commandServiceEnumMap.put(WeekEnum.WEB, () -> System.out.println("周三大盘震荡"));
for (Map.Entry<WeekEnum, CommandService> weekEnumCommandService : commandServiceEnumMap.entrySet()) {
WeekEnum week = weekEnumCommandService.getKey();
System.out.println(week.name() + "的策略:");
weekEnumCommandService.getValue().action();
}
}
- Result
MON的策略:
周一白酒涨停
TUE的策略:
周二有色跌停
WEB的策略:
周三大盘震荡