枚举是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. 初步了解JPA

    想当初07.08年的时候,毕业之季,正思考着离开学校要去做什么工作.为了有一份薪资不错,可以长久发展,也正是自己喜欢的行业.于是乎决定投身于计算机行业.当年正是JAVA的火热时期.到处都是JAVA培训 ...

  2. SharePoint Site "Language Settings"功能与CSOM的对应

    博客地址:http://blog.csdn.net/FoxDave SharePoint网站中的语言设置:"Language Settings",可以用CSOM通过Site的一些 ...

  3. linux-rpm

    1.         RPM本地安装 RPM包管理员(简称RPM,全称为The RPM Package Manager)是在Linux下广泛使用的软件包管理器.RPM此名词可能是指.rpm的文件格式的 ...

  4. Android 数据库管理— — —创建数据库

    <?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android=" ...

  5. java开发环境

    java开发环境搭建   文中主要内容来自:http://blog.csdn.net/cxwen78/article/details/6400798 .文章对原文有所改动. 1. 开发工具获取 开发工 ...

  6. 【LeetCode】Roman to Integer & Integer to Roman

    Roman to Integer Given a roman numeral, convert it to an integer. Input is guaranteed to be within t ...

  7. JAVA(2)

    java面向对象编程的四大特征: 1.抽象 2.封装 3.继承 4.多态 封装 //职员 class Clerk { public String name; //private私有的 private ...

  8. 关于调用deleteRowsAtIndexPaths withRowAnimation方法出现错误

    通常原因是因为 这个方法的调用与数据源有关. 检测1.你的数据源是否写死了. 2.调用该方法前你是否移除相关的数据源 相关的核心代码如下: - (NSInteger)tableView:(UITabl ...

  9. C++学习笔记34:泛型编程拓展3

    输入流迭代器 #include <iostream> #include <iterator> #include <algorithm> #include <v ...

  10. ionic 开发APP 安装配置详解以及 cordova 环境配置详细过程

    整个安装过程:     1. jdk 1.7.2   (http://www.oracle.com/technetwork/java/javase/downloads/index.html) 安装好之 ...