想让你的java代码更漂亮,用枚举吧
枚举是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代码更漂亮,用枚举吧的更多相关文章
- 【转】Lombok:让JAVA代码更优雅
原文地址:http://blog.didispace.com/java-lombok-1/ 关于Lombok,其实在网上可以找到很多如何使用的文章,但是很少能找到比较齐全的整理.我也一直寻思着想写一篇 ...
- 提高Java代码质量:使用枚举定义常量(转)
一.分析 常量的声明是每一个项目中不可或缺的,在Java1.5之前,我们只有两种方式的声明:类常量和接口常量.不过,在1.5版之后有了改进,即新增了一种常量声明方式,枚举常量.代码如下: enum ...
- 让JAVA代码跑得更快
本文简单介绍一下在写代码过程中用到的一些让JAVA代码更高效的技巧. 1. 将一些系统资源放在池中(如数据库连接, 线程等) 在standalone的应用中, 数据库连接池可以使用一些开源的连接池 ...
- JAVA8-让代码更优雅之List排序
先定义一个实体类 @Data @AllArgsConstructor @NoArgsConstructor public class Human { private String name; priv ...
- java虚拟机jvm启动后java代码层面发生了什么?
java虚拟机jvm启动后java代码层面发生了什么? 0000 我想验证的事情 java代码在被编译后可以被jdk提供的java命令进行加载和运行, 在我们的程序被运行起来的时候,都发生了什么事情, ...
- 如何更规范化编写Java 代码
如何更规范化编写Java 代码 Many of the happiest people are those who own the least. But are we really so happy ...
- 如何更规范化的编写JAVA 代码
如何更规范的编写JAVA代码 一.MyBatis 不要为了多个查询条件而写 1 = 1 当遇到多个查询条件,使用where 1=1 可以很方便的解决我们的问题,但是这样很可能会造成非常大的性能损失, ...
- Java 8 Lambda表达式,让你的代码更简洁
Lambda表达式是Java 8一个非常重要的新特性.它像方法一样,利用很简单的语法来定义参数列表和方法体.目前Lambda表达式已经成为高级编程语言的标配,像Python,Swift等都已经支持La ...
- 使用 Google Guava 美化你的 Java 代码
文章转载自:http://my.oschina.net/leejun2005/blog/172328 目录:[ - ] 1-使用 GOOGLE COLLECTIONS,GUAVA,STATIC IMP ...
随机推荐
- 设置table距离顶部位置
//UIEdgeInsetsMake———— UIEdgeInsets insets = {top, left, bottom, right} self.tableView.contentInset ...
- 如何在tomcat中如何部署java EE项目
如何在tomcat中如何部署java EE项目 1.直接把项目复制到Tomcat安装目录的webapps目录中,这是最简单的一种Tomcat项目部署的方法,也是初学者最常用的方法.2.在tomcat安 ...
- Mysql封装
<?php header("content-type:text/html;charset=utf-8"); class db{ //私有的静态属性 private ...
- linux内核分析——扒开系统调用的三层皮(下)
20135125陈智威 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ” 实验 ...
- Android 游戏教程让人物动起来
在这里给大家分享Android游戏教程怎样让人物动起来,话不多说了,直接进入正题. 一. 准备工作 首先要准备好要使用的人物动作图和地形图.把它分割成16个不同的动作,循环播放同一行的4个不同 ...
- 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 ...
- 小学生四则运算出题程序 无操作界面java版 简单的运用java中一些基本操作
这是本学期java课中实验大纲里的第一个实验,这里简单做了一个无用户界面版本. import java.util.Random; import java.util.Scanner; public cl ...
- sqlite实现oracle的rownum功能
SELECT (SELECT COUNT(*) FROM [table] AS t2 WHERE t2.name <= t1.name) AS rowNum, id, name FROM [ta ...
- 论文ei,sci检索,JCR-SCI分区,中科院分区连接
https://jcr.incites.thomsonreuters.com/JCRJournalHomeAction.action?SID=B1-bQgax2FJ7EsyZ9muP6O5loc77S ...
- 十分钟了解分布式计算:Spark
Spark是一个通用的分布式内存计算框架,本文主要研讨Spark的核心数据结构RDD的设计思路,及其在内存上的容错.内容基于论文 Zaharia, Matei, et al. "Resili ...