阿里Java开发规约(2)
本文是对阿里插件中规约的详细解释二,关于插件使用,请参考这里
- 及时清理不再使用的代码段或配置信息。 说明:对于垃圾代码或过时配置,坚决清理干净,避免程序过度臃肿,代码冗余
Positive example: For codes which are temporarily removed and likely to be reused, use /// to add a reasonable note.
public static void hello() {
/// Business is stopped temporarily by the owner.
// Business business = new Business();
// business.active();
System.out.println("it's finished");
} - 后台输送给页面的变量必须加感叹号,${var}——中间加感叹号!。 说明:如果var=null或者不存在,那么${var}会直接显示在页面上
<input type="text" name="email" value="$!email"/>
<input type="text" name="email" value="$!{email}"/> - 在if/else/for/while/do语句中必须使用大括号,即使只有一行代码,避免使用下面的形式:if (condition) statements;
- 在subList场景中,高度注意对原列表的修改,会导致子列表的遍历、增加、删除均产生ConcurrentModificationException异常;
注:原因从源码可以看出,当子list添加删除元素时,也会相应添加删除本list。但反之就会出现异常。至于Java为何要这样设计,不得而知。Negative example:
List<String> originList = new ArrayList<String>();
originList.add("22");
List<String> subList = originList.subList(0, 1);
//warn
originList.add("22"); 在一个switch块内,每个case要么通过break/return等来终止,要么注释说明程序将继续执行到哪一个case为止;在一个switch块内,都必须包含一个default语句并且放在最后,即使它什么代码也没有。
- 在使用正则表达式时,利用好其预编译功能,可以有效加快正则匹配速度。 说明:不要在方法体内定义:Pattern pattern = Pattern.compile(规则);
注:为代码效率考虑public class XxxClass {
// Use precompile
private static Pattern NUMBER_PATTERN = Pattern.compile("[0-9]+");
public Pattern getNumberPattern() {
// Avoid use Pattern.compile in method body.
Pattern localPattern = Pattern.compile("[0-9]+");
return localPattern;
}
} 多线程并行处理定时任务时,Timer运行多个TimeTask时,只要其中之一没有捕获抛出的异常,其它任务便会自动终止运行,使用ScheduledExecutorService则没有这个问题。
注:当处理多个并行任务时,如果需要线程异常不互相影响,用ScheduledExecutorService代替Timer//org.apache.commons.lang3.concurrent.BasicThreadFactory
ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1,
new BasicThreadFactory.Builder().namingPattern("example-schedule-pool-%d").daemon(true).build());
executorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
//do something
}
},initialDelay,period, TimeUnit.HOURS);- 定义DO/DTO/VO等POJO类时,不要加任何属性默认值。(注:跟前面的用包装类一脉相承)
- 对于Service和DAO类,基于SOA的理念,暴露出来的服务一定是接口,内部的实现类用Impl的后缀与接口区别
注:SOA:面向服务架构(Service-Oriented Architecture) - 常量命名应该全部大写,单词间用下划线隔开,力求语义表达完整清楚,不要嫌名字长
public class ConstantNameDemo { /**
* max stock count
*/
public static final Long MAX_STOCK_COUNT = 50000L; - 异常类命名使用Exception结尾
- 循环体内,字符串的联接方式,使用StringBuilder的append方法进行扩展。
必须回收自定义的ThreadLocal变量,尤其在线程池场景下,线程经常会被复用,如果不清理自定义的 ThreadLocal变量,可能会影响后续业务逻辑和造成内存泄露等问题。尽量在代理中使用try-finally块进行回收。
- 所有的包装类对象之间值的比较,全部使用equals方法比较。
说明:对于Integer var=?在-128至127之间的赋值,Integer对象是在IntegerCache.cache产生,会复用已有对象,这个区间内的Integer值可以直接使用==进行判断,
但是这个区间之外的所有数据,都会在堆上产生,并不会复用已有对象,这是一个大坑,推荐使用equals方法进行判断。 Integer a = 235;
Integer b = 235;
if (a.equals(b)) {
//相等
} - 所有的抽象方法(包括接口中的方法)必须要用javadoc注释、除了返回值、参数、异常说明外,还必须指出该方法做什么事情,实现什么功能。 说明:如有实现和调用注意事项,请一并说明。
/**
* fetch data by rule id
*
* @param ruleId rule id
* @param page page number
* @param jsonContext json format context
* @return Result<XxxxDO>
*/
Result<XxxxDO> fetchDataByRuleId(Long ruleId, Integer page, String jsonContext); - 所有的枚举类型字段必须要有注释,说明每个数据项的用途。
- 所有的类都必须添加创建者信息。
- 所有的覆写方法,必须加@Override注解。(注:可以让编译器提前发现错误)
- 所有编程相关的命名均不能以下划线或美元符号开始
- 抽象类命名使用Abstract或Base开头
- 方法内部单行注释,在被注释语句上方另起一行,使用//注释。方法内部多行注释使用/* */注释。注意与代码对齐。
- 方法名、参数名、成员变量、局部变量都统一使用lowerCamelCase,必须遵从驼峰形式
- 注意 Math.random() 这个方法返回是double类型,注意取值的范围[0,1)(能够取到零值,注意除零异常),如果想获取整数类型的随机数,不要将x放大10的若干倍然后取整,直接使用Random对象的nextInt或者nextLong方法。
Negative example:
Long randomLong =(long) (Math.random() * 10); Positive example:
Long randomLong = new Random().nextLong(); - 测试类命名以它要测试的类的名称开始,以Test结尾
- 类、类属性、类方法的注释必须使用javadoc规范,使用/**内容*/格式,不得使用//xxx方式和/*xxx*/方式。
说明:在IDE编辑窗口中,javadoc方式会提示相关注释,生成javadoc可以正确输出相应注释;在IDE中,工程调用方法时,不进入方法即可悬浮提示方法、参数、返回值的意义,提高阅读效率。
/**
*
* XXX class function description.
*
*/
public class XxClass implements Serializable {
private static final long serialVersionUID = 113323427779853001L;
/**
* id
*/
private Long id;
/**
* title
*/
private String title; /**
* find by id
*
* @param ruleId rule id
* @param page start from 1
* @return Result<Xxxx>
*/
public Result<Xxxx> funcA(Long ruleId, Integer page) {
return null;
}
} - 类名使用UpperCamelCase风格,必须遵从驼峰形式,但以下情形例外:(领域模型的相关命名)DO / BO / DTO / VO / DAO
- 线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
说明:Executors各个方法的弊端:
1)newFixedThreadPool和newSingleThreadExecutor:
主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至OOM。
2)newCachedThreadPool和newScheduledThreadPool:
主要问题是线程数最大数是Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至OOM。 Positive example 1:
//org.apache.commons.lang3.concurrent.BasicThreadFactory
ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1,
new BasicThreadFactory.Builder().namingPattern("example-schedule-pool-%d").daemon(true).build()); Positive example 2:
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
.setNameFormat("demo-pool-%d").build(); //Common Thread Pool
ExecutorService pool = new ThreadPoolExecutor(5, 200,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy()); pool.execute(()-> System.out.println(Thread.currentThread().getName()));
pool.shutdown();//gracefully shutdown Positive example 3:
<bean id="userThreadPool"
class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
<property name="corePoolSize" value="10" />
<property name="maxPoolSize" value="100" />
<property name="queueCapacity" value="2000" /> <property name="threadFactory" value= threadFactory />
<property name="rejectedExecutionHandler">
<ref local="rejectedExecutionHandler" />
</property>
</bean>
//in code
userThreadPool.execute(thread); - 获取当前毫秒数:System.currentTimeMillis(); 而不是new Date().getTime();
注:这是从效率考虑,不用生成冗余的DAT对象 说明:如果想获取更加精确的纳秒级时间值,用System.nanoTime。在JDK8中,针对统计时间等场景,推荐使用Instant类。
public class TimeMillisDemo {
public static void main(String args[]) {
// Positive example:
long a = System.currentTimeMillis();
// Negative example:
long b = new Date().getTime(); System.out.println(a);
System.out.println(b);
}
}返回类型为基本数据类型,return包装数据类型的对象时,自动拆箱有可能产生NPE
public int method() {
Integer a = null;
return a;
}- 避免Random实例被多线程使用,虽然共享该实例是线程安全的,但会因竞争同一seed 导致的性能下降。说明:Random实例包括java.util.Random 的实例或者 Math.random()的方式。
说明:使用线程池的好处是减少在创建和销毁线程上所花的时间以及系统资源的开销,解决资源不足的问题。如果不使用线程池,有可能造成系统创建大量同类线程而导致消耗完内存或者“过度切换”的问题。 ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
.setNameFormat("demo-pool-%d").build();
ExecutorService singleThreadPool = new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy()); singleThreadPool.execute(()-> System.out.println(Thread.currentThread().getName()));
singleThreadPool.shutdown(); 避免用Apache Beanutils进行属性的copy。
说明:Apache BeanUtils性能较差,可以使用其他方案比如Spring BeanUtils, Cglib BeanCopier。
TestObject a = new TestObject();
TestObject b = new TestObject();
a.setX(b.getX());
a.setY(b.getY());- 避免通过一个类的对象引用访问此类的静态变量或静态方法,无谓增加编译器解析成本,直接用类名来访问即可。(注:需要了解JVM机制)
- 除常用方法(如getXxx/isXxx)等外,不要在条件判断中执行复杂的语句,将复杂逻辑判断的结果赋值给一个有意义的布尔变量,以提高可读性。
说明:很多if语句内的逻辑相当复杂,阅读者需要分析条件表达式的最终结果,才能明确什么样的条件执行什么样的语句,那么,如果阅读者分析逻辑表达式错误呢? Negative example:
if ((file.open(fileName, "w") != null) && (...) || (...)) {
...
} Positive example:
boolean existed = (file.open(fileName, "w") != null) && (...) || (...);
if (existed) {
...
} - 集合初始化时,指定集合初始值大小。
说明:HashMap使用如下构造方法进行初始化,如果暂时无法确定集合大小,那么指定默认值(16)即可。 Negative example:
Map<String, String> map = new HashMap<String, String>(); Positive example:
Map<String, String> map = new HashMap<String, String>(16);
阿里Java开发规约(2)的更多相关文章
- 阿里Java开发规约插件使用
刚刚的云栖大会上,阿里巴巴公布了这款酝酿已久的Java开发规约插件,对于国内开发者来说是一次轻松提高自己代码规范的机会. 安装方法 IDEA安装方法: settings >> plugin ...
- 阿里Java开发规约笔记
借助阿里开发规约,回顾一下Java开发编码基础方面的知识,结合自己使用中遇到的问题,记录一下规约中以前翻过的错.有共鸣的问题. 1.覆写方法时要加上@Override注解.重写一个类型T的equals ...
- 阿里Java开发规约(1)
本文是对阿里插件中规约的详细解释一,关于插件使用,请参考这里 1. ArrayList的subList结果不可强转成ArrayList,否则会抛出ClassCastException异常. 说明:禁止 ...
- 阿里Java开发规约【摘录】
1.命名规约 [强制]类名使用UpperCamelCase风格,必须遵从驼峰形式,但以下情形例外:(领域模型的相关命名)DO / BO / DTO / VO等. 正例:MarcoPolo / User ...
- 阿里和Google的JAVA开发规约
<阿里 JAVA开发规约> 阿里巴巴Java开发手册终极版v1.3.0.pdf 出处:github地址:https://github.com/alibaba/p3c <Google ...
- 为什么阿里Java规约要求谨慎使用SimpleDateFormat
前言 在阿里Java开发规约中,有强制性的提到SimpleDateFormat 是线程不安全的类 ,在使用的时候应当注意线程安全问题,如下: 其实之前已经介绍过使用JDK1.8的DateTimeFor ...
- 阿里巴巴 Java 开发规约插件初体验
阿里巴巴 Java 开发手册 又一次来谈<阿里巴巴 Java 开发手册>,经过这大半年的版本迭代,这本阿里工程师们总结出来避免写出那么多 Bug 的规范,对于 Java 开发者简直就是必备 ...
- 阿里巴巴Java开发规约及插件安装
[上海尚学堂编辑整理]10.14日,阿里巴巴在杭州云栖大会上,正式发布了由阿里巴巴 P3C 项目组,经过 近一年的持续研发,正式发布众所期待的 <阿里巴巴 Java 开发规约>的扫描插件. ...
- 阿里java代码检测工具p3c
阿里在杭州云栖大会上,正式发布众所期待的<阿里巴巴Java开发规约>扫描插件! 该插件由阿里巴巴P3C项目组研发.这个项目组是阿里巴巴开发爱好者自发组织形成的虚拟项目组,把<阿里巴巴 ...
随机推荐
- Oracle pl/sql 显示游标和隐式游标
显示游标 一.定义语法: CURSOR <游标名> IS <SELECT 语句> [FOR UPDATE | FOR UPDATE ...
- java的类型转换问题。int a = 123456;short b = (short)a;System.out.println(b);为什么结果是-7616?
这个从二进制来解释: int 是 32 位,也就是最多能表示长度为 32 位的二进制整数.第一位是符号位,表示正负,0 表示正的,1 表示负的.当首位为 1(为负)时,把所有的位取反(0 变成 1,1 ...
- ARC102D All Your Paths are Different Lengths
传送门 题目大意 让你构造一个有向图,使得从1到n有L条不同路径且长度分别是0~L-1. 分析 我们不难想到每一对相邻点之间连一条权值为0的边,之后二进制分解,将每一对点之间连一个权值为2^i的边,但 ...
- 269D Maximum Waterfall
传送门 题目大意 给出一些墙,水从高往低流,每次只能到达一面墙,选择一个路径,使得路径上的流量的最小值最大. 分析 这是一道经典的扫描线题,我们发现能够合法的线段对数至多只有n对.将一条线段拆成两个点 ...
- ARC061E Snuke's Subway Trip
传送门 题目大意 已知某城市的地铁网由一些地铁线路构成,每一条地铁线路由某一个公司运营,该城市规定:若乘坐同一公司的地铁,从开始到换乘只需要一块钱,换乘其他公司的价格也是一块钱,问从1号地铁站到n号地 ...
- vue 之 模板字符串
传统的JavaScript语言,输出模板通常是这样的写的. $('#result').append( 'There are <b>' + basket.count + '</b> ...
- Inheritance with EF Code First: Part 1 – Table per Hierarchy (TPH)
以下三篇文章是Entity Framework Code-First系列中第七回:Entity Framework Code-First(7):Inheritance Strategy 提到的三篇.这 ...
- Java多线程并发学习-进阶大纲
1.synchronized 的实现原理以及锁优化? 2.volatile 的实现原理? 3.Java 的信号灯? 4.synchronized 在静态方法和普通方法的区别? 5.怎么实现所有线程在等 ...
- winform播放视频(windows media player)
1.找到windows media player 工具箱常规下边右键,右键弹窗点击“选择项”,选择工具箱窗口点击“COM组件”,找到 Windows Media Player 勾选,点击确定 2.使用 ...
- ASP.NET MVC底层原理与框架
前言 鄙人有一毛病,喜欢钻研原理性的东西,感觉只知道怎么用还不太够,更想知道如何实现的以及为什么会这样. 暑假的时候做积分系统是第一次接触MVC,感觉MVC就是一个框架,分为Module ,view和 ...