《VIP代码规约》读书笔记
2021-04-24 11:12:28 3 举报
AI智能生成
唯品会代码规约
作者其他创作
大纲/内容
(七) 基本类型与字符串
Rule 1. 原子数据类型(int等)与包装类型(Integer等)的使用原则
1、 需要序列化的POJO类属性使用包装数据类型
2、RPC方法的返回值和参数使用包装数据类型
3、局部变量尽量使用基本数据类型
分支主题
Rule 2. 原子数据类型与包装类型的转换原则
1、自动转换(AutoBoxing)有一定成本,调用者与被调用函数间尽量使用同一类型,减少默认转换
分支主题
2、自动拆箱有可能产生NPE,要注意处理
Rule 3. 数值equals比较的原则
1、所有包装类对象之间值的比较,全部使用equals方法比较 【*】
2、BigDecimal需要使用compareTo() 【*】
3、Atomic* 系列,不能使用equals方法 【*】
4、 double及float的比较,要特殊处理 【*】
分支主题
Rule 4. 数字类型的计算原则
1、数字运算表达式,因为先进行等式右边的运算,再赋值给等式左边的变量,所以等式两边的类型要一致 【*】
分支主题
2、数字取模的结果不一定是正数,负数取模的结果仍然负数【*】
3、double 或 float 计算时有不可避免的精度问题
尽量用double而不用float,但如果是金融货币的计算,则必须使用如下选择:
选项1, 使用性能较差的BigDecimal。BigDecimal还能精确控制四舍五入或是其他取舍的方式。
选项2, 在预知小数精度的情况下,将浮点运算放大为整数计数,比如货币以"分"而不是以"元"计算。
Rule 5. 如果变量值仅有有限的可选值,用枚举类来定义常量
Rule 6. 字符串拼接的原则
1、当字符串拼接不在一个命令行内写完,而是存在多次拼接时(比如循环),使用StringBuilder的append()
2、字符串拼接对象时,不要显式调用对象的toString()【*】
3、使用StringBuilder,而不是有所有方法都有同步修饰符的StringBuffer【*】
4、当拼接后字符串的长度远大于16时,指定StringBuilder的大概长度,避免容量不足时的成倍扩展
5、如果字符串长度很大且频繁拼接,可考虑ThreadLocal重用StringBuilder对象
6、字符操作时,优先使用字符参数,而不是字符串,能提升性能
Rule 7. 利用好正则表达式的预编译功能,可以有效加快正则匹配速度
分支主题
(八) 集合处理
Rule 1. 底层数据结构是数组的集合,指定集合初始大小
Rule 2. 尽量使用新式的foreach语法遍历Collection与数组
Rule 3. 不要在foreach循环里进行元素的remove/add操作,remove元素可使用Iterator方式 【*】
Rule 4. 使用entrySet遍历Map类集合Key/Value,而不是keySet方式进行遍历【*】
Rule 5. 当对象用于集合时,下列情况需要重新实现hashCode()和equals()【*】
1) 以对象做为Map的KEY时;
2) 将对象存入Set时。
另外,对象放入集合后,会影响hashCode(),equals()结果的属性,将不允许修改。
Rule 6. 高度注意各种Map类集合Key/Value能不能存储null值的情况【*】
Rule 7. 长生命周期的集合,里面内容需要及时清理,避免内存泄漏
长生命周期集合包括下面情况,都要小心处理。
1) 静态属性定义;
2) 长生命周期对象的属性;
3) 保存在ThreadLocal中的集合。
另外,如果使用WeakHashMap保存对象,当对象本身失效时,就不会因为它在集合中存在引用而阻止回收。但JDK的WeakHashMap并不支持并发版本,如果需要并发可使用Guava Cache的实现。
Rule 8. 集合如果存在并发修改的场景,需要使用线程安全的版本
1) 著名的反例,HashMap扩容时,遇到并发修改可能造成100%CPU占用。
推荐使用java.util.concurrent(JUC) 工具包中的并发版集合,如ConcurrentHashMap等,优于使用Collections.synchronizedXXX()系列函数进行同步化封装(等价于在每个方法都加上synchronized关键字)。
例外:ArrayList所对应的CopyOnWriteArrayList,每次更新时都会复制整个数组,只适合于读多写很少的场景。如果频繁写入,可能退化为使用Collections.synchronizedList(list)。
2) 即使线程安全类仍然要注意函数的正确使用。
例如:即使用了ConcurrentHashMap,但直接是用get/put方法,仍然可能会多线程间互相覆盖。
Rule 9. 正确使用集合泛型的通配符
1) 如果集合要被读取,定义成 <? extends T>
2) 如果集合要被写入,定义成 <? super T>
Rule 10. List , List<?> 与 List<Object> 的选择
Rule 11. 如果Key只有有限的可选值,先将Key封装成Enum,并使用EnumMap
Rule 12. Array 与 List互转的正确写法
分支主题
Arrays.asList(array),如果array是原始类型数组如int[],会把整个array当作List的一个元素,String[] 或 Foo[]则无此问题。
Collections.addAll()实际是循环加入元素,性能相对较低,同样会把int[]认作一个元素。
(九) 并发处理
Rule 1. 创建线程或线程池时请指定有意义的线程名称,方便出错时回溯 【*】
Rule 2. 尽量使用线程池来创建线程
除特殊情况,尽量不要自行创建线程,更好的保护线程资源。
同理,定时器也不要使用Timer,而应该使用ScheduledExecutorService。
因为Timer只有单线程,不能并发的执行多个在其中定义的任务,而且如果其中一个任务抛出异常,整个Timer也会挂掉,而ScheduledExecutorService只有那个没捕获到异常的任务不再定时执行,其他任务不受影响。
Rule 3. 线程池不允许使用 Executors去创建,避资源耗尽风险 【*】
Executors返回的线程池对象的弊端 :
1)FixedThreadPool 和 SingleThreadPool:
2)CachedThreadPool 和 ScheduledThreadPool:
应通过new ThreadPoolExecutor(xxx,xxx,xxx,xxx)这样的方式,更加明确线程池的运行规则,合理设置Queue及线程池的core size和max size,建议使用vjkit封装的ThreadPoolBuilder。
Rule 4. 正确停止线程【*】
Thread.stop()不推荐使用,强行的退出太不安全,会导致逻辑不完整,操作不原子,已被定义成Deprecate方法。
停止单条线程,执行Thread.interrupt()。
停止线程池:
ExecutorService.shutdown(): 不允许提交新任务,等待当前任务及队列中的任务全部执行完毕后退出;
ExecutorService.shutdownNow(): 通过Thread.interrupt()试图停止所有正在执行的线程,并不再处理还在队列中等待的任务。
最优雅的退出方式是先执行shutdown(),再执行shutdownNow(),vjkit的 ThreadPoolUtil 进行了封装。
Rule 5. 编写可停止的Runnable
1、正确处理InterruptException
因为InterruptException异常是个必须处理的Checked Exception,所以run()所调用的子函数很容易吃掉异常并简单的处理成打印日志,但这等于停止了中断的传递,外层函数将收不到中断请求,继续原有循环或进入下一个堵塞。
分支主题
2、主循环及进入阻塞状态前要判断线程状态
分支主题
Rule 6. Runnable中必须捕获一切异常 【*】
如果Runnable中没有捕获RuntimeException而向外抛出,会发生下列情况:
1) ScheduledExecutorService执行定时任务,任务会被中断,该任务将不再定时调度,但线程池里的线程还能用于其他任务。
2) ExecutorService执行任务,当前线程会中断,线程池需要创建新的线程来响应后续任务。
3) 如果没有在ThreadFactory设置自定义的UncaughtExceptionHanlder,则异常最终只打印在System.err,而不会打印在项目的日志中。
Rule 7. 全局的非线程安全的对象可考虑使用ThreadLocal存放 【*】
Rule 8. 缩短锁
1) 能锁区块,就不要锁整个方法体;
2)能用对象锁,就不要用类锁。
Rule 9. 选择分离锁,分散锁甚至无锁的数据结构
分离锁:
1) 读写分离锁ReentrantReadWriteLock,读读之间不加锁,仅在写读和写写之间加锁;
2) Array Base的queue一般是全局一把锁,而Linked Base的queue一般是队头队尾两把锁。
分散锁(又称分段锁)
1)如JDK7的ConcurrentHashMap,分散成16把锁;
2)对于经常写,少量读的计数器,推荐使用JDK8或vjkit封装的LongAdder对象性能更好(内部分散成多个counter,减少乐观锁的使用,取值时再相加所有counter)
无锁的数据结构:
1)完全无锁无等待的结构,如JDK8的ConcurrentHashMap;
2)基于CAS的无锁有等待的数据结构,如AtomicXXX系列。
Rule 10. 基于ThreadLocal来避免锁
Rule 11. 规避死锁风险
Rule 12. volatile修饰符,AtomicXX系列的正确使用
Rule13. 延时初始化的正确写法
(十) 异常处理
Rule 1. 创建异常的消耗大,只用在真正异常的场景 【*】
构造异常时,需要获得整个调用栈,有一定消耗。
不要用来做流程控制,条件控制,因为异常的处理效率比条件判断低。
发生概率较高的条件,应该先进行检查规避,比如:IndexOutOfBoundsException,NullPointerException等,所以如果代码里捕获这些异常通常是个坏味道。
Rule 2. 在特定场景,避免每次构造异常
1) 如果异常的message不变,将异常定义为静态成员变量;
2) 如果异常的message会变化,则对静态的异常实例进行clone()再修改message。
3)自定义异常,也可以考虑重载fillStackTrace()为空函数,但相对没那么灵活,比如无法按场景指定一层的StackTrace。
Rule 3. 自定义异常,建议继承 RuntimeException
Rule 4. 异常日志应包含排查问题的足够信息
分支主题
Rule 5. 异常抛出的原则
1、尽量使用JDK标准异常,项目标准异常
2、根据调用者的需要来定义异常类,直接使用 RuntimeException是允许的
Rule 6. 异常捕获的原则
1、按需要捕获异常,捕获 Exception 或 Throwable 是允许的
2、多个异常的处理逻辑一致时,使用JDK7的语法避免重复代码
Rule 7. 异常处理的原则
1、捕获异常一定要处理;如果故意捕获并忽略异常,须要注释写明原因
2、异常处理不能吞掉原异常,要么在日志打印,要么在重新抛出的异常里包含原异常
3、如果不想处理异常,可以不进行捕获。但最外层的业务使用者,必须处理异常,将其转化为用户可以理解的内容
Rule 8. finally块的处理原则
1、必须对资源对象、流对象进行关闭,或使用语法try-withresource 【*】
2、 如果处理过程中有抛出异常的可能,也要做try-catch,否则finally块中抛出的异常,将代替try块中抛出的异常 【*】
3、不能在finally块中使用return,finally块中的return将代替try块中的return及throw Exception【*】
(十一) 日志规约
Rule 1. 应用中不可直接使用日志库(Log4j、Logback)中的API,而应使用日志框架SLF4J中的API 【*】
Rule 2. 对不确定会否输出的日志,采用占位符或条件判断
logger.debug("Processing trade with id: {} symbol : {} ", id, symbol);
if (logger.isDebugEnabled()) { xxxx.... }
Rule 3. 对确定输出,而且频繁输出的日志,采用直接拼装字符串的方式
Rule 4. 尽量使用异步日志
Rule 5. 禁止使用性能很低的System.out()打印日志信息 【*】
Rule 6. 禁止配置日志框架输出日志打印处的类名,方法名及行号的信息【*】
Rule 7. 谨慎地记录日志,避免大量输出无效日志,信息不全的日志
Rule 8. 使用warn级别而不是error级别,记录外部输入参数错误的情况
(十二) 其他规约
Rule 1. 尽量不要让魔法值(即未经定义的数字或字符串常量)直接出现在代码中
Rule 2. 时间获取的原则
1)获取当前毫秒数System.currentTimeMillis() 而不是new Date().getTime(),后者的消耗要大得多。
2)如果要获得更精确的,且不受NTP时间调整影响的流逝时间,使用System.nanoTime()获得机器从启动到现在流逝的纳秒数。
3)如果希望在测试用例中控制当前时间的值,则使用vjkit的Clock类封装,在测试和生产环境中使用不同的实现。
Rule 3. 变量声明尽量靠近使用的分支
Rule 4. 不要像C那样一行里做多件事情
Rule 5. 不要为了性能而使用JNI本地方法
Rule 6. 正确使用反射,减少性能损耗
Rule 7. 可降低优先级的常见代码检查规则
1、接口内容的定义中,去除所有modifier,如public等。 (多个public也没啥,反正大家都看惯了)
2、工具类,定义private构造函数使其不能被实例化。(命名清晰的工具类,也没人会去实例化它,对静态方法通过类来访问也能避免实例化)
https://vipshop.github.io/vjtools/#/standard/
(一) 命名规约
Rule 1. 禁止拼音缩写,避免阅读者费劲猜测;尽量不用拼音,除非中国式业务词汇没有通用易懂的英文对应。【*】
禁止: DZ[打折] / getPFByName() [评分]
尽量避免:Dazhe / DaZhePrice
Rule 2. 禁止使用非标准的英文缩写 【*】
反例: AbstractClass 缩写成 AbsClass;condition 缩写成 condi。
Rule 3. 禁用其他编程语言风格的前缀和后缀 【*】
在其它编程语言中使用的特殊前缀或后缀,如_name , name_ , mName , i_name ,在Java中都不建议使用。
Rule 4. 命名的好坏,在于其“模糊度”【*】
1、 如果上下文很清晰,局部变量可以使用 list 这种简略命名, 否则应该使用 userList 这种更清晰的命名。
2、 禁止 a1, a2, a3 这种带编号的没诚意的命名方式。
3、 方法的参数名叫 bookList ,方法里的局部变量名叫 theBookList 也是很没诚意。
4、 如果一个应用里同时存在 Account、AccountInfo、AccountData 类,或者一个类里同时有 getAccountInfo()、getAccountData() , save()、store() 的函数,阅读者将非常困惑。
5、 callerId 与 calleeId , mydearfriendswitha 与 mydearfriendswithb 这种拼写极度接近,考验阅读者眼力的。
Rule 5. 包名全部小写。点分隔符之间尽量只有一个英语单词,即使有多个单词也不使用下划线或大小写分隔【*】
正例: com.vip.javatool
反例: com.vip.java_tool, com.vip.javaTool
Rule 6. 类名与接口名使用UpperCamelCase风格,遵从驼峰形式【*】
Tcp, Xml等缩写也遵循驼峰形式,可约定例外如:DTO/ VO等。
正例:UserId / XmlService / TcpUdpDeal / UserVO
反例:UserID / XMLService / TCPUDPDeal / UserVo
Rule 7. 方法名、参数名、成员变量、局部变量使用lowerCamelCase风格,遵从驼峰形式
正例: localValue / getHttpMessage();
Rule 8. 常量命名全大写,单词间用下划线隔开。力求语义表达完整清楚,不要嫌名字长【*】
正例: MAX_STOCK_COUNT
反例: MAX_COUNT
例外:当一个static final字段不是一个真正常量,比如不是基本类型时,不需要使用大写命名。
private static final Logger logger = Logger.getLogger(MyClass.class)
例外:枚举常量推荐全大写,但如果历史原因未遵循也是允许的,所以我们修改了Sonar的规则。
Rule 9. 如果使用到了通用的设计模式,在类名中体现,有利于阅读者快速理解设计思想【*】
正例:OrderFactory, LoginProxy ,ResourceObserver
Rule 10. 枚举类名以Enum结尾; 抽象类使用Abstract或Base开头;异常类使用Exception结尾;测试类以它要测试的类名开始,以Test结尾【*】
正例:DealStatusEnum, AbstractView,BaseView, TimeoutException,UserServiceTest
Rule 11. 实现类尽量用Impl的后缀与接口关联,除了形容能力的接口【*】
正例:CacheServiceImpl 实现 CacheService接⼝。
返例: Foo 实现 Translatable接⼝。
Rule 12. POJO类中布尔类型的变量名,不要加is前缀,否则部分框架解析会引起序列化错误【*】
反例:Boolean isSuccess的成员变量,它的GET方法也是isSuccess(),部分框架在反射解析的
Rule 13. 避免成员变量,方法参数,局部变量的重名复写,引起混淆 【*】
类的私有成员变量名,不与父类的成员变量重名
方法的参数名/局部变量名,不与类的成员变量重名 (getter/setter例外)
(二) 格式规约
Rule 1. 使用项目组统一的代码格式模板,基于IDE自动的格式化 【*】
IDE的默认代码格式模板,能简化绝大部分关于格式规范(如空格,括号)的描述。
统一的模板,并在接手旧项目先进行一次全面格式化,可以避免, 不同开发者之间,因为格式不统一产生代码合并冲突,或者代码变更日志中因为格式不同引起的变更,掩盖了真正的逻辑变更。
设定项目组统一的行宽,建议120。
设定项目组统一的缩进方式(Tab或二空格,四空格均可),基于IDE自动转换。
VIP代码格式化模板:https://github.com/vipshop/vjtools/tree/master/standard/formatter
Rule 2. IDE的text file encoding设置为UTF-8; IDE中文件的换行符使用Unix格式,不要使用Windows格式 【*】
Rule 3. 用小括号来限定运算优先级
示例:if ((a == b) && (c == d))
Rule 4. 类内方法定义的顺序,不要“总是在类的最后添加新方法”
顺序依次是:构造函数 > (公有方法>保护方法>私有方法) > getter/setter方法。
当一个类有多个构造方法,或者多个同名的重载方法,这些方法应该放置在一起。其中参数较多的方法在后面。
作为调用者的方法,尽量放在被调用的方法前面。
Rule 5. 通过空行进行逻辑分段
不同组的变量之间,不同业务逻辑的代码行之间,插入一个空行,起逻辑分段的作用。
而联系紧密的变量之间、语句之间,则尽量不要插入空行。
Rule 6. 避免IDE格式化
对于一些特殊场景(如使用大量的字符串拼接成一段文字,或者想把大量的枚举值排成一列),为了避免IDE自动格式化,土办法是把注释符号//加在每一行的末尾,但这有视觉的干扰,可以使用@formatter:off和@formatter:on来包装这段代码,让IDE跳过它。
(三) 注释规约
Rule 1. 基本的注释要求
第一、能够准确反应设计思想和代码逻辑;
第二、能够描述业务含义,使别的程序员能够迅速了解到代码背后的信息。
Rule 2. 通过更清晰的代码来避免注释
Rule 3. 删除空注释,无意义注释
《Clean Code》建议,如果没有想说的,不要留着IDE自动生成的,空的@param,@return,@throws 标记,让代码更简洁。
Rule 4. 避免创建人,创建日期,及更新日志的注释
Rule 5. 代码修改的同时,注释也要进行相应的修改。尤其是参数、返回值、异常、核心逻辑等的修改 【*】
Rule 6. 类、类的公有成员、方法的注释必须使用Javadoc规范,使用/** xxx */格式,不得使用 //xxx 方式 【*】
Rule 7. JavaDoc中不要为了HTML格式化而大量使用HTML标签和转义字符
Rule 8. 注释不要为了英文而英文
Rule 9. TODO标记,清晰说明代办事项和处理人
Rule 10. 合理处理注释掉的代码
如果后续会恢复此段代码,在目标代码上方用/// 说明注释动机,而不是简单的注释掉代码。
如果很大概率不再使用,则直接删除(版本管理工具保存了历史代码)。
(四) 方法设计
Rule 1. 方法的长度度量、
方法尽量不要超过100行,或其他团队共同商定的行数。
另外,方法长度超过8000个字节码时,将不会被JIT编译成二进制码。
Rule 2. 方法的语句在同一个抽象层级上 ---> 将功能抽成函数,提高复用
Rule 3. 为了帮助阅读及方法内联,将小概率发生的异常处理及其他极小概率进入的代码路径,封装成独立的方法
Rule 4. 尽量减少重复的代码,抽取方法
Rule 5. 方法参数最好不超过3个,最多不超过7个
1)如果多个参数同属于一个对象,直接传递对象。
2)将多个参数合并为一个新创建的逻辑对象。
3)将函数拆分成多个函数,让每个函数所需的参数减少。
Rule 6. 下列情形,需要进行参数校验
1) 调用频次低的方法。
2) 执行时间开销很大的方法。此情形中,参数校验时间几乎可以忽略不计,但如果因为参数错误导致中间执行回退,或者错误,代价更大。
3) 需要极高稳定性和可用性的方法。
4) 对外提供的开放接口,不管是RPC/HTTP/公共类库的API接口。
如果使用Apache Validate 或 Guava Precondition进行校验,并附加错误提示信息时,注意不要每次校验都做一次字符串拼接。
Rule 7. 下列情形,不需要进行参数校验
1) 极有可能被循环调用的方法。
2) 底层调用频度比较高的方法。毕竟是像纯净水过滤的最后一道,参数错误不太可能到底层才会暴露问题。
3) 被声明成private,或其他只会被自己代码所调用的方法,如果能够确定在调用方已经做过检查,或者肯定不会有问题则可省略。
Rule 8. 禁用assert做参数校验
Rule 9. 返回值可以为Null,可以考虑使用JDK8的Optional类
Rule 10. 返回值可以为内部数组和集合
Rule 11. 不能使用有继承关系的参数类型来重载方法
Rule 12. 正被外部调用的接口,不允许修改方法签名,避免对接口的调用方产生影响
Rule 13. 不使用 @Deprecated 的类或方法
Rule 14. 不使用不稳定方法,如com.sun.*包下的类,底层类库中internal包下的类
(五) 类设计
Rule 1. 类成员与方法的可见性最小化
Rule 2. 减少类之间的依赖
Rule 3. 定义变量与方法参数时,尽量使用接口而不是具体类
Rule 4. 类的长度度量
Rule 5. 构造函数如果有很多参数,且有多种参数组合时,建议使用Builder模式
分支主题
Rule 6. 构造函数要简单,尤其是存在继承关系的时候
Rule 7. 所有的子类覆写方法,必须加 @Override 注解
Rule 8. 静态方法不能被子类覆写。
Rule 9. 静态方法访问的原则
1、避免通过一个类的对象引用访问此类的静态变量或静态方法,直接用类名来访问即可
2、除测试用例,不要static import 静态方法
3、尽量避免在非静态方法中修改静态成员变量的值
Rule 10. 内部类的定义原则
内部类也常用作回调函数类,在JDK8下建议写成Lambda
内部类分匿名内部类,内部类,静态内部类
1) 匿名内部类 与 内部类,按需使用
2) 静态内部类 与 内部类,优先使用静态内部类
Rule 11. 使用getter/setter方法,还是直接public成员变量的原则。
使用getter/setter,好处是可以进一步的处理
1. 通过隐藏setter方法使得成员变量只读
2. 增加简单的校验逻辑
3. 增加简单的值处理,值类型转换等
例外:有些序列化框架只能从getter/setter反射,不能直接反射public成员变量。
Rule 12. POJO类必须覆写toString方法 【*】
Rule 13. hashCode和equals方法的处理,遵循如下规则
只要重写equals,就必须重写hashCode。 而且选取相同的属性进行运算。 【*】
只选取真正能决定对象是否一致的属性,而不是所有属性,可以改善性能。
对不可变对象,可以缓存hashCode值改善性能(比如String就是例子)。
类的属性增加时,及时重新生成toString,hashCode和equals方法。
Rule 14. 使用IDE生成toString,hashCode和equals方法。 【*】
Rule 15. Object的equals方法容易抛空指针异常,应使用常量或确定非空的对象来调用equals 【*】
Rule 16. 除了保持兼容性的情况,总是移除无用属性、方法与参数【*】
Rule 17. final关键字与性能无关,仅用于下列不可修改的场景
1)定义类及方法时,类不可继承,方法不可覆写;
2)定义基本类型的函数参数和变量,不可重新赋值;
3) 定义对象型的函数参数和变量,仅表示变量所指向的对象不可修改,而对象自身的属性是可以修改的。
Rule 18. 得墨忒耳法则,不要和陌生人说话
以下调用,一是导致了对A对象的内部结构(B,C)的紧耦合,二是连串的调用很容易产生NPE,因此链式调用尽量不要过长。
(六) 控制语句
Rule 1. if, else, for, do, while语句必须使用大括号,即使只有单条语句【*】
曾经试过合并代码时,因为没加括号,单条语句合并成两条语句后,仍然认为只有单条语句,另一条语句在循环外执行。
Rule 2. 少用if-else方式,多用哨兵语句式以减少嵌套层次
Rule 3. 限定方法的嵌套层次
Rule 4. 布尔表达式中的布尔运算符(&&,||)的个数不超过4个,将复杂逻辑判断的结果赋值给一个有意义的布尔变量名,以提高可读性
Rule 5. 简单逻辑,善用三目运算符,减少if-else语句的编写
Rule 6. 减少使用取反的逻辑
Rule 7. 表达式中,能造成短路概率较大的逻辑尽量放前面,使得后面的判断可以免于执行
Rule 8. switch的规则
1)在一个switch块内,每个case要么通过break/return等来终止,要么注释说明程序将继续执行到哪一个case为止;
2)在一个switch块内,都必须包含一个default语句并且放在最后,即使它什么代码也没有。
分支主题
Rule 9. 循环体中的语句要考量性能,操作尽量移至循环体外处理
1)不必要的耗时较大的对象构造;
2)不必要的try-catch(除非出错时需要循环下去)。
Rule 10. 能用while循环实现的代码,就不用do-while循环
0 条评论
下一页