枚举是java 5之后添加的一个重要特性,这个特性不能提高性能,但是能让java程序员写出更优雅的代码。

我之前看到过挺多介绍java枚举的不错的帖子,我也来参与以下这个话题。

1. 枚举基本用法

 /**
* 消息的类型,是请求还是回应
* @author leo
*
*/
public enum ReqOrRes {
req,res;
}

这应该是枚举最简单的用法了,即使是这样简单的使用,也能给我们带来方便,

ReqOrRes.req.name() == "req"

ReqOrRes.valueOf("req") == ReqOrRes.req  , 通过name 和valueOf这两个枚举内置的方法,可以方便的将枚举在字符串和枚举之间转化。

2. 枚举中带方法,将处理逻辑写在枚举类中,将调用框架和业务逻辑分离

/**
* 列举调度server与slave之间的所有通信报文类型,每个类型的具体描述见com.zdcin.msgbean包,<br>
* 每种消息有两个方法供外部调用,根据消息是在哪里产生,对应一方需实现processReq方法,产生消息的一方需要实现processRes方法。
* @author leo
*
*/
public enum MsgType {// MsgType有两个主要方法,processReq,和processRes, 用于完成处理各种类型的请求消息和响应消息的逻辑 /** slave获取clientid
*
*/
GET_CLIENT_ID {
@Override
public void processReq(String json) {// 覆盖父类MsgType中的同名方法,processRes方法在另外一端实现,这个方法的意思是处理请求,并发回响应信息
GET_CLIENT_ID_req req = MsgUtils.getGson().fromJson(json, GET_CLIENT_ID_req.class);
GET_CLIENT_ID_res res = new GET_CLIENT_ID_res(req);
。。。。。
//用clientid做key找到连接,把消息发回去
Client.sendMsgToSlave(res.clientId, res);
}
},
/** 已经分配过id的slave每次连接到server都要用该命令通知server建立连接 */
CONNECT {
@Override
public void processReq(String json) {
CONNECT_req req = MsgUtils.getGson().fromJson(json, CONNECT_req.class);
。。。。。
}
}, /** 任务指定 */
TASK_ASSIGN {
@Override
public void processRes(String json) {
//不用实现
}
},
/** 心跳 */
HEART_BEAT { @Override
public void processReq(String json) {
HEART_BEAT_req req = MsgUtils.getGson().fromJson(json, HEART_BEAT_req.class);
if ("00X".equalsIgnoreCase(req.meta.clientId)) {
return;
}
HEART_BEAT_res res = new HEART_BEAT_res(req);
Client.sendMsgToSlave(req.meta.clientId, res);
} @Override
public void processRes(String json) {
//接收就行,不用处理
}
};
//------------ 到这里,枚举类型定义结束了,下边是各个枚举都可以用的公共方法
/**
* 消息有在调度server产生的,又在slave上产生的,
* 在调度器上产生的消息,slave需要实现processReq方法,并且slave需要返回res消息给调度器,调度器就需要实现processRes方法;
* 如果消息是在slave上产生(如主动上报状态的消息),上述流程就反过来。
* @param json
*/
public void processReq(String json){//父类定义的方法
throw new RuntimeException(this.name() + ".processReq() method not implement.");
} /**
* 消息有在调度server产生的,又在slave上产生的,
* 在调度器上产生的消息,slave需要实现processReq方法,并且slave需要返回res消息给调度器,调度器就需要实现processRes方法;
* 如果消息是在slave上产生(如主动上报状态的消息),上述流程就反过来。
* @param json
*/
public void processRes(String json){//父类定义的方法
throw new RuntimeException(this.name() + ".processRes() method not implement.");
}
}

上述枚举类的作用是定义消息类型,同时在processReq和processRes方法中实现处理各种请求和响应消息的逻辑,这只是消息一端的代码,一般消息中processReq和processRes只需要出现一次,在消息的另一段,对称的实现缺少的那个方法就可以。

这个枚举类用起来大概是这个样子的:

public class ReciveWork implements Runnable {

    private String json;
private Meta meta; public ReciveWork(Meta meta, String json) {
this.meta = meta;
this.json = json;
} @Override
public void run() {
try {
switch (meta.reqOrRes) {
case req://根据消息是请求类型还是响应类型,来决定是调用 processReq方法还是 processRes方法。
meta.msgType.processReq(json);// meta.msgType 就是MsgType中的CONNECT, GET_CLIENT_ID等枚举,这里不确定是哪一个,但是可以确定他们会有processReq方法,这样就可以优雅的动态分发消息给合适的处理者了
break; case res:
// 检查重发队列,如果在队列中,取消重发
Client.notifyToStopRetry(meta);
// 先检查有对方有没有处理错误,有的话,直接记录日志,不调用后续的处理方法了, 相关的错误恢复工作可以在定时任务中进行。
BaseResMsg baseres = MsgUtils.getGson().fromJson(json, BaseResMsg.class);
if (baseres.errCode != 0) {
Main.log.error("error in " + baseres.meta.msgType.name() + "_res, [errCode, errMsg]=["
+ baseres.errCode + ", " + baseres.errMsg + "]");
} else {
meta.msgType.processRes(json);
} break;
}
} catch (Exception e) {
Main.log.error(
"error in " + meta.msgType.name() + ".process" + meta.reqOrRes.name() + ", " + e.getMessage(), e);
}
} }

worker类实现了Runnable接口,可以放在线程池里,多线程并行分发处理。

现在看,效果还不错吧,如果不用枚举,估计少不了一堆if else分支判断,或者是基于抽象类的模式,每个消息类型写一个子类,去做实现,应该不会比这简单。

3. 带数值可叠加的枚举

/**
*
* @author leo
*
*/
public enum AppMonitorType {
/**
* 读权限
*/
read(1),
/**
* 写权限
*/
write(2),
/**
* 执行权限
*/
exec(4),
/**
* 特殊权限
*/
spic(8); private int bitValue;
private AppMonitorType(int v) {//私有的构造方法,只能类初始化时使用,如exec(4),
this.bitValue = v;
}
public int getBitValue() {// 返回枚举对应的整形值,如 exec(4) 中的4
return this.bitValue;
} //将数值转换成权限列表, 这个方法是静态的, 直接AppMonitoryType.parseBitValue()
public static List<AppMonitorType> parseBitValue(int bitValue) {
if (bitValue <= 0) {
return null;
}
List<AppMonitorType> list = new ArrayList<AppMonitorType>();
for (AppMonitorType type : AppMonitorType.values()) {
if ((type.bitValue & bitValue) == type.bitValue) {
list.add(type);
}
}
return list;
}
// 将权限列表转换成数值, 注意这个方法是静态的,用的时候 直接AppMonitorType.getBitValue()
public static int getBitValue(List<AppMonitorType> list) {
int i = 0;
for (AppMonitorType type : list) {
i |= type.bitValue;
}
return i;
}
}

由于涉及一些业务信息,我临时用 read write等代替了原来的枚举, 不过用法是一样的, 这个例子比较简单,不管用什么方式实现都不会很难,当数据量多一些,逻辑复杂一些的时候,枚举的好处应该会体现的更明显。

你有关于枚举使用的一些奇妙的想法吗,欢迎提出来,大家一起进步,我也想进一步去发现。

原文地址:http://www.cnblogs.com/zdcin/p/3155057.html

想让你的java代码更漂亮,用枚举吧的更多相关文章

  1. 【转】Lombok:让JAVA代码更优雅

    原文地址:http://blog.didispace.com/java-lombok-1/ 关于Lombok,其实在网上可以找到很多如何使用的文章,但是很少能找到比较齐全的整理.我也一直寻思着想写一篇 ...

  2. 提高Java代码质量:使用枚举定义常量(转)

    一.分析  常量的声明是每一个项目中不可或缺的,在Java1.5之前,我们只有两种方式的声明:类常量和接口常量.不过,在1.5版之后有了改进,即新增了一种常量声明方式,枚举常量.代码如下: enum ...

  3. 让JAVA代码跑得更快

    本文简单介绍一下在写代码过程中用到的一些让JAVA代码更高效的技巧. 1.   将一些系统资源放在池中(如数据库连接, 线程等) 在standalone的应用中, 数据库连接池可以使用一些开源的连接池 ...

  4. JAVA8-让代码更优雅之List排序

    先定义一个实体类 @Data @AllArgsConstructor @NoArgsConstructor public class Human { private String name; priv ...

  5. java虚拟机jvm启动后java代码层面发生了什么?

    java虚拟机jvm启动后java代码层面发生了什么? 0000 我想验证的事情 java代码在被编译后可以被jdk提供的java命令进行加载和运行, 在我们的程序被运行起来的时候,都发生了什么事情, ...

  6. 如何更规范化编写Java 代码

    如何更规范化编写Java 代码 Many of the happiest people are those who own the least. But are we really so happy ...

  7. 如何更规范化的编写JAVA 代码

    如何更规范的编写JAVA代码 一.MyBatis 不要为了多个查询条件而写 1 = 1 当遇到多个查询条件,使用where 1=1 可以很方便的解决我们的问题,但是这样很可能会造成非常大的性能损失, ...

  8. Java 8 Lambda表达式,让你的代码更简洁

    Lambda表达式是Java 8一个非常重要的新特性.它像方法一样,利用很简单的语法来定义参数列表和方法体.目前Lambda表达式已经成为高级编程语言的标配,像Python,Swift等都已经支持La ...

  9. 使用 Google Guava 美化你的 Java 代码

    文章转载自:http://my.oschina.net/leejun2005/blog/172328 目录:[ - ] 1-使用 GOOGLE COLLECTIONS,GUAVA,STATIC IMP ...

随机推荐

  1. ie7 用 clearfix 清除浮动时遇到的问题

    <!doctype html> <html> <head> <style> .fr{float:right;display:inline} li{bor ...

  2. FreeCAD鼠标操作指南

    鼠标控制模式 跳转至: 导航. 搜索 freeCAD鼠标的控制模式由多个命令构成,用于三维空间的视觉导航和控制显示对象.freecad支持多个鼠标导航方式.默认的导航方式是被称为“CAD导航”,非常简 ...

  3. 《java中异常和错误》

    异常和错误的区别. 异常: 在Java中程序的错误主要是语法错误和语义错误,一个程序在编译和运行时出现的错误我们统一称之为异常,它是VM(虚拟机)通知你的一种方式,通过这种方式,VM让你知道,你(开发 ...

  4. flask SQLAlchemy中一对多的关系实现

    SQLAlchemy是Python中比较优秀的orm框架,在SQLAlchemy中定义了多种数据库表的对应关系, 其中一对多是一种比较常见的关系.利用flask sqlalchemy实现一对多的关系如 ...

  5. 64位系统下找不到office 32位组件

    如果系统式64位的,而装的是32位的office软件,在运行栏中输入命令:dcomcnfg,打开组件服务管理窗口,但是却发现找不到Microsoft Excel程序, 这主要是64位系统的问题,exc ...

  6. BZOJ 4521 手机号码

    SB数位dp. 我的貌似要特判9999999999的情况. #include<iostream> #include<cstdio> #include<cstring> ...

  7. java java.lang.NoClassDefFoundError 的解决办法

    以简单而经典的 "HelloWorld.java" 为例 不含包层次的HelloWorld.Java public class HelloWorld { public static ...

  8. caffe 基本知识简介

    很多不错的网页: 1.http://alanse7en.github.io/caffedai-ma-jie-xi-1/ 主要介绍基本caffe知识 interace 接口 API中的‘I’ Caffe ...

  9. Those who are not capable of Control their moods are not supposed to be ready for their baby.

    I hate these Stupid Selfish People. We need Children Caring Organization.

  10. JavaScript闭包模型

      JavaScript闭包模型 -----  [原创翻译]2016-09-01  09:32:22 < 一>  闭包并不神秘 本文利用JavaScript代码来阐述闭包,目的是为了使普通 ...