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

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

1. 枚举基本用法

  1. /**
  2. * 消息的类型,是请求还是回应
  3. * @author leo
  4. *
  5. */
  6. public enum ReqOrRes {
  7. req,res;
  8. }

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

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

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

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

  1. /**
  2. * 列举调度server与slave之间的所有通信报文类型,每个类型的具体描述见com.zdcin.msgbean包,<br>
  3. * 每种消息有两个方法供外部调用,根据消息是在哪里产生,对应一方需实现processReq方法,产生消息的一方需要实现processRes方法。
  4. * @author leo
  5. *
  6. */
  7. public enum MsgType {// MsgType有两个主要方法,processReq,和processRes, 用于完成处理各种类型的请求消息和响应消息的逻辑
  8.  
  9. /** slave获取clientid
  10. *
  11. */
  12. GET_CLIENT_ID {
  13. @Override
  14. public void processReq(String json) {// 覆盖父类MsgType中的同名方法,processRes方法在另外一端实现,这个方法的意思是处理请求,并发回响应信息
  15. GET_CLIENT_ID_req req = MsgUtils.getGson().fromJson(json, GET_CLIENT_ID_req.class);
  16. GET_CLIENT_ID_res res = new GET_CLIENT_ID_res(req);
  17. 。。。。。
  18. //用clientid做key找到连接,把消息发回去
  19. Client.sendMsgToSlave(res.clientId, res);
  20. }
  21. },
  22. /** 已经分配过id的slave每次连接到server都要用该命令通知server建立连接 */
  23. CONNECT {
  24. @Override
  25. public void processReq(String json) {
  26. CONNECT_req req = MsgUtils.getGson().fromJson(json, CONNECT_req.class);
  27. 。。。。。
  28. }
  29. },
  30.  
  31. /** 任务指定 */
  32. TASK_ASSIGN {
  33. @Override
  34. public void processRes(String json) {
  35. //不用实现
  36. }
  37. },
  38. /** 心跳 */
  39. HEART_BEAT {
  40.  
  41. @Override
  42. public void processReq(String json) {
  43. HEART_BEAT_req req = MsgUtils.getGson().fromJson(json, HEART_BEAT_req.class);
  44. if ("00X".equalsIgnoreCase(req.meta.clientId)) {
  45. return;
  46. }
  47. HEART_BEAT_res res = new HEART_BEAT_res(req);
  48. Client.sendMsgToSlave(req.meta.clientId, res);
  49. }
  50.  
  51. @Override
  52. public void processRes(String json) {
  53. //接收就行,不用处理
  54. }
  55. };
    //------------ 到这里,枚举类型定义结束了,下边是各个枚举都可以用的公共方法
  56. /**
  57. * 消息有在调度server产生的,又在slave上产生的,
  58. * 在调度器上产生的消息,slave需要实现processReq方法,并且slave需要返回res消息给调度器,调度器就需要实现processRes方法;
  59. * 如果消息是在slave上产生(如主动上报状态的消息),上述流程就反过来。
  60. * @param json
  61. */
  62. public void processReq(String json){//父类定义的方法
  63. throw new RuntimeException(this.name() + ".processReq() method not implement.");
  64. }
  65.  
  66. /**
  67. * 消息有在调度server产生的,又在slave上产生的,
  68. * 在调度器上产生的消息,slave需要实现processReq方法,并且slave需要返回res消息给调度器,调度器就需要实现processRes方法;
  69. * 如果消息是在slave上产生(如主动上报状态的消息),上述流程就反过来。
  70. * @param json
  71. */
  72. public void processRes(String json){//父类定义的方法
  73. throw new RuntimeException(this.name() + ".processRes() method not implement.");
  74. }
  75. }

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

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

  1. public class ReciveWork implements Runnable {
  2.  
  3. private String json;
  4. private Meta meta;
  5.  
  6. public ReciveWork(Meta meta, String json) {
  7. this.meta = meta;
  8. this.json = json;
  9. }
  10.  
  11. @Override
  12. public void run() {
  13. try {
  14. switch (meta.reqOrRes) {
  15. case req://根据消息是请求类型还是响应类型,来决定是调用 processReq方法还是 processRes方法。
  16. meta.msgType.processReq(json);// meta.msgType 就是MsgType中的CONNECT, GET_CLIENT_ID等枚举,这里不确定是哪一个,但是可以确定他们会有processReq方法,这样就可以优雅的动态分发消息给合适的处理者了
  17. break;
  18.  
  19. case res:
  20. // 检查重发队列,如果在队列中,取消重发
  21. Client.notifyToStopRetry(meta);
  22. // 先检查有对方有没有处理错误,有的话,直接记录日志,不调用后续的处理方法了, 相关的错误恢复工作可以在定时任务中进行。
  23. BaseResMsg baseres = MsgUtils.getGson().fromJson(json, BaseResMsg.class);
  24. if (baseres.errCode != 0) {
  25. Main.log.error("error in " + baseres.meta.msgType.name() + "_res, [errCode, errMsg]=["
  26. + baseres.errCode + ", " + baseres.errMsg + "]");
  27. } else {
  28. meta.msgType.processRes(json);
  29. }
  30.  
  31. break;
  32. }
  33. } catch (Exception e) {
  34. Main.log.error(
  35. "error in " + meta.msgType.name() + ".process" + meta.reqOrRes.name() + ", " + e.getMessage(), e);
  36. }
  37. }
  38.  
  39. }

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

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

3. 带数值可叠加的枚举

  1. /**
  2. *
  3. * @author leo
  4. *
  5. */
  6. public enum AppMonitorType {
  7. /**
  8. * 读权限
  9. */
  10. read(1),
  11. /**
  12. * 写权限
  13. */
  14. write(2),
  15. /**
  16. * 执行权限
  17. */
  18. exec(4),
  19. /**
  20. * 特殊权限
  21. */
  22. spic(8);
  23.  
  24. private int bitValue;
  25. private AppMonitorType(int v) {//私有的构造方法,只能类初始化时使用,如exec(4),
  26. this.bitValue = v;
  27. }
  28. public int getBitValue() {// 返回枚举对应的整形值,如 exec(4) 中的4
  29. return this.bitValue;
  30. }
  31.  
  32. //将数值转换成权限列表, 这个方法是静态的, 直接AppMonitoryType.parseBitValue()
  33. public static List<AppMonitorType> parseBitValue(int bitValue) {
  34. if (bitValue <= 0) {
  35. return null;
  36. }
  37. List<AppMonitorType> list = new ArrayList<AppMonitorType>();
  38. for (AppMonitorType type : AppMonitorType.values()) {
  39. if ((type.bitValue & bitValue) == type.bitValue) {
  40. list.add(type);
  41. }
  42. }
  43. return list;
  44. }
  45. // 将权限列表转换成数值, 注意这个方法是静态的,用的时候 直接AppMonitorType.getBitValue()
  46. public static int getBitValue(List<AppMonitorType> list) {
  47. int i = 0;
  48. for (AppMonitorType type : list) {
  49. i |= type.bitValue;
  50. }
  51. return i;
  52. }
  53. }

由于涉及一些业务信息,我临时用 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. 设置table距离顶部位置

    //UIEdgeInsetsMake———— UIEdgeInsets insets = {top, left, bottom, right} self.tableView.contentInset ...

  2. 如何在tomcat中如何部署java EE项目

    如何在tomcat中如何部署java EE项目 1.直接把项目复制到Tomcat安装目录的webapps目录中,这是最简单的一种Tomcat项目部署的方法,也是初学者最常用的方法.2.在tomcat安 ...

  3. Mysql封装

    <?php header("content-type:text/html;charset=utf-8"); class db{    //私有的静态属性    private ...

  4. linux内核分析——扒开系统调用的三层皮(下)

    20135125陈智威 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ” 实验 ...

  5. Android 游戏教程让人物动起来

    在这里给大家分享Android游戏教程怎样让人物动起来,话不多说了,直接进入正题. 一. 准备工作     首先要准备好要使用的人物动作图和地形图.把它分割成16个不同的动作,循环播放同一行的4个不同 ...

  6. Error running app: This version of Android Studio is incompatible with the Gradle Plugin used. Try disabling Instant Run.

    转自:http://blog.csdn.net/qq_15807167/article/details/51984920 参考:http://stackoverflow.com/questions/3 ...

  7. 小学生四则运算出题程序 无操作界面java版 简单的运用java中一些基本操作

    这是本学期java课中实验大纲里的第一个实验,这里简单做了一个无用户界面版本. import java.util.Random; import java.util.Scanner; public cl ...

  8. sqlite实现oracle的rownum功能

    SELECT (SELECT COUNT(*) FROM [table] AS t2 WHERE t2.name <= t1.name) AS rowNum, id, name FROM [ta ...

  9. 论文ei,sci检索,JCR-SCI分区,中科院分区连接

    https://jcr.incites.thomsonreuters.com/JCRJournalHomeAction.action?SID=B1-bQgax2FJ7EsyZ9muP6O5loc77S ...

  10. 十分钟了解分布式计算:Spark

    Spark是一个通用的分布式内存计算框架,本文主要研讨Spark的核心数据结构RDD的设计思路,及其在内存上的容错.内容基于论文 Zaharia, Matei, et al. "Resili ...