不管是方法,变量,仍是函数的取名,不要嫌弃名称太长,只要可以表示清楚含义就能够了。java
中括号是数组类型的一部分,数组定义以下:String[] args;算法
在《Thinking in Java》这边书里面,是这么解释的:spring
POJO类中的任何布尔类型的变量,都不要加 is,不然部分框架解析会引发序列化错
误。数据库
大部分经典的书籍都有提到这一点,老话题了。apache
A) Service/DAO 层方法命名规约
1) 获取单个对象的方法用 get 作前缀。
2) 获取多个对象的方法用 list 作前缀。
3) 获取统计值的方法用 count 作前缀。
4) 插入的方法用 save(推荐)或 insert 作前缀。
5) 删除的方法用 remove(推荐)或 delete 作前缀。
6) 修改的方法用 update 作前缀。编程
这一点确实很重要,有时候本身都作不到,规范大于编码。windows
String key="Id#taobao_"+tradeId; cache.put(key, value);
魔法数值:是指在代码中直接出现的数值,而只有在这个数值记述的那部分代码中才能明确了解其含义。设计模式
在这里进行扩充下:api
魔法数字的例子数组
int priceTable[] = new int[16]; //ERROR:这个16究竟有何含义呢?
使用了带名字的数值的例子
解决方法:
static final int PRICE_TABLE_MAX = 16; //OK:带名字
int price Table[] = new int [PRICE_TABLE_MAX]; //OK:名字的含义是很清楚的
有时候作项目,心急如焚时,就会忘记
下例中实参的”a”,后边必需要有一个空格
method("a", "b", "c");
IDE 的 text file encoding 设置为 UTF-8; IDE 中文件的换行符使用 Unix 格式,不
要使用 windows 格式
若是在抽象类中对方法签名进行修改,其实现类会立刻编
译报错
《Effective Java》这本书已经说的清清楚楚了,你们能够去啃啃这一节的内容。
相同参数类型,相同业务含义,才可使用Java的可变参数,避免使用 Object。可变参数必须放置在参数列表的最后
public User getUsers(String type, Integer... ids);
1) 全部的POJO类属性必须使用包装数据类型。
2) RPC方法的返回值和参数必须使用包装数据类型。
3) 全部的局部变量推荐使用基本数据类型。
说明:POJO类属性没有初值是提醒使用者在须要使用时,必须本身显式地进行赋值,任何
NPE 问题,或者入库检查,都由使用者来保证。
正例:数据库的查询结果多是 null,由于自动拆箱,用基本数据类型接收有 NPE 风险。
反例:某业务的交易报表上显示成交总额涨跌状况,即正负 x%,x 为基本数据类型,调用的
RPC 服务,调用不成功时,返回的是默认值,页面显示:0%,这是不合理的,应该显示成中划
线-。因此包装数据类型的 null 值,可以表示额外的信息,如:远程调用失败,异常退出
避免反序列失败
若是有初始化逻辑,请放在init方法中
其实这是符合一个方法只作一件事的原则。
使用工具类 source> generate toString 时,若是继承了另外一个 POJO 类,注意在前面加一下 super.toString。说明:在方法执行抛出异常时,能够直接调用 POJO 的 toString()方法打印其属性值,便于排查问题。
貌似咱们项目框架中,这一点没有作到
类内方法定义顺序依次是:公有方法或保护方法 > 私有方法 > getter/setter 方法。
说明: 公有方法是类的调用者和维护者最关心的方法,首屏展现最好;保护方法虽然只是子类
关心,也多是“模板设计模式”下的核心方法;而私有方法外部通常不须要特别关心,是一
个黑盒实现;由于方法信息价值较低,全部 Service 和 DAO 的 getter/setter 方法放在类体最
后。
final可提升程序响应效率,声明成final的状况:
1) 不须要从新赋值的变量,包括类属性、局部变量。
2) 对象参数前加final,表示不容许修改引用的指向。
3) 类方法肯定不容许被重写
String 重写了 hashCode 和 equals 方法,因此咱们能够很是愉快地使用String对象做
为 key 来使用。
传入的是类型彻底同样的数组,大小就是 list.size()。
反例:直接使用 toArray 无参方法存在问题,此方法返回值只能是 Object[]类,若强转其它
类型数组将出现 ClassCastException 错误。
正例:
List<String> list = new ArrayList<String>(2); list.add("guan"); list.add("bao"); String[] array = new String[list.size()]; array = list.toArray(array);
说明:使用 toArray 带参方法,入参分配的数组空间不够大时,toArray 方法内部将从新分配
内存空间,并返回新数组地址;若是数组元素大于实际所需,下标为[ list.size() ]的数组
元素将被置为 null,其它数组元素保持原值,所以最好将方法入参数组大小定义与集合元素
个数一致
它的 add/remove/clear 方法会抛出 UnsupportedOperationException 异常。
说明: asList 的返回对象是一个 Arrays 内部类,并无实现集合的修改方法。 Arrays.asList
体现的是适配器模式,只是转换接口,后台的数据还是数组。
String[] str = new String[] { "a", "b" }; List list = Arrays.asList(str); 第一种状况:list.add("c"); 运行时异常。 第二种状况:str[0]= "gujin"; 那么 list.get(0)也会随之修改。
remove元素请使用Iterator方式,若是并发操做,须要对 Iterator 对象加锁。
反例:
List a = new ArrayList();
a.add(“1”);
a.add(“2”);
for (String temp : a) {
if(“1”.equals(temp)){
a.remove(temp);
}
}
ArrayList 尽可能使用 ArrayList(int initialCapacity) 初始化。
keySet 实际上是遍历了 2 次,一次是转为 Iterator 对象,另外一次是从 hashMap 中取出 key
所对应的 value。而 entrySet 只是遍历了一次就把 key 和 value 都放到了 entry 中,效率更
高。若是是 JDK8,使用Map.foreach 方法。
这一点能够参考《Thinking in Java》第17章容器深刻研究这一章
避免使用List的contains 方法进行遍历去重操做。
不但节约数据库表空间、节约索引存储,更重要的是提高检索速度。
须要哪些字段必须明确写明。
说明:1)增长查询分析器解析成本。2)增减字段容易与resultMap配置不一致。
若实在避免不了,须要仔细评估 in 后边的集合元素数量,控制在 1000 个以内。
异常信息应该包括两类信息:案发现场信息和异常堆栈信息。若是不处理,那么往上
抛。
logger.error(各种参数或者对象 toString + "_" + e.getMessage(), e);
这一点我有点不支持,好比下面的代码:
//阿里巴巴建议的写法 if(a > 0){ System.out.println("....."); } //对于if逻辑中只有一句话,我习惯下面这么些 if(a > 0) System.out.println(".....");
那个比较好本身对比吧!!!
存储过程难以调试和扩展,更没有移植性
反正咱们公司没用。
if(condition){ … return obj; }
事实上这个是《重构-改善既有代码设计》这本书所提倡的,多些卫语句,具体什么是卫语句,我在下面参考文章中有一篇连接,你们能够去看。
正例:
//伪代码以下 InputStream stream = file.open(fileName, "w"); if (stream != null) { … }
反例:
if (file.open(fileName, “w”) != null)) {
…
}
SimpleDateFormat 是线程不安全的类,通常不要定义为 static 变量,若是定义为static,必须加锁,或者使用 DateUtils 工具类。
正例:注意线程安全,使用 DateUtils。亦推荐以下处理:
private static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() { @Override protected DateFormat initialValue() { return new SimpleDateFormat("yyyy-MM-dd"); } };
说明:若是是 JDK8 的应用,可使用 instant 代替 Date,Localdatetime 代替 Calendar,
Datetimeformatter 代替 Simpledateformatter,官方给出的解释:simple beautiful strong
immutable thread-safe。
避免 Random 实例被多线程使用,虽然共享该实例是线程安全的,但会因竞争同一 seed
致使的性能降低。
说明:Random 实例包括 java.util.Random 的实例或者 Math.random()实例。
正例:在 JDK7 以后,能够直接使用 API ThreadLocalRandom,在 JDK7 以前,能够作到每一个线
程一个实例。
类、类属性、类方法的注释必须使用 javadoc 规范,使用/*内容/格式,不得使用//xxx 方式。
方法内部单行注释,在被注释语句上方另起一行,使用//注释。方法内部多行注释使
用/* */注释,注意与代码对齐
能够参考《代码整洁之道》这本书中的注释这一章,里面内容更加纤细。
对于“明确中止使用的代码和配置”,如方法、变量、类、配置文件、动态配置属性
等要坚定从程序中清理出去,避免形成过多垃圾。清理这类垃圾代码是技术气场,不要有这样
的观念:“不作不错,多作多错”。
而不是 new Date().getTime();
说明:若是想获取更加精确的纳秒级时间值,用 System.nanoTime。在 JDK8 中,针对统计时
间等场景,推荐使用 Instant 类。
【强制】线程资源必须经过线程池提供,不容许在应用中自行显式建立线程。
说明: 使用线程池的好处是减小在建立和销毁线程上所花的时间以及系统资源的开销,解决资
源不足的问题。若是不使用线程池,有可能形成系统建立大量同类线程而致使消耗完内存或者
“过分切换”的问题。
事实上,我我的建议,每一个方法都要写上建立者姓名,这样出现问题比较好排查
出现问题,分分钟弄死它。
尤为是参数、返回值、异常、核心逻辑等的修改。
说明:这点很难彻底作到,但不少次的故障都是由于数据结构自增加,结果形成内存被吃光。
由于有些异常具有以“周”为频次发生的特色。
或者使用占位符的方式。
说明:logger.debug(“Processing trade with id: ” + id + ” symbol: ” + symbol); 若是
日志级别是 warn,上述日志不会打印,可是会执行字符串拼接操做,若是 symbol 是对象,会
执行 toString()方法,浪费了系统资源,执行了上述操做,最终日志却没有打印。
正例:(条件)
if (logger.isDebugEnabled()) { logger.debug("Processing trade with id: " + id + " symbol: " + symbol); }
正例:(占位符)
logger.debug("Processing trade with id: {} and symbol : {} ", id, symbol);
注意及时处理这些标记,经过标记扫描,常常清理此类标记。线上故障有时候就是来源于这些标记处的代码。
说明:Apache BeanUtils 性能较差,可使用其余方案好比 spring BeanUtils, Cglib
BeanCopier。
之后会专门写一篇关于这方面的文章,敬请期待
致使 CPU 飙升的问题
appName_logType_logName.log。logType:日志类型,推荐分类有 stats/desc/monitor/visit
等;logName:日志描述。这种命名的好处:经过文件名就可知道日志文件属于什么应用,什么类型,什么目的,也有利于归类查找。
能用无锁数据结构,就不要用锁;能锁区块,就不要锁整个方法体;能用对象锁,就不要用类锁。
对于公司外的 http/api 开放接口必须使用“错误码”;而应用内部推荐异常抛出;跨应用间 RPC 调用优先考虑使用 Result 方式,封装 isSuccess、“错误码”、“错误简短信息”。
说明:关于 RPC 方法返回方式使用 Result 方式的理由:
1)使用抛异常返回方式,调用方若是没有捕获到就会产生运行时错误。
2)若是不加栈信息,只是 new 自定义异常,加入本身的理解的 error message,对于调用
端解决问题的帮助不会太多。若是加了栈信息,在频繁调用出错的状况下,数据序列化和传输
的性能损耗也是问题。
有选择地输出 info 日志;若是使用 warn 来记录刚上线时的业务行为信息,必定要注意日志输出量的问题,避免把服务器磁盘撑爆,并记得及时删除这些观察日志。
说明:大量地输出无效日志,不利于系统性能提高,也不利于快速定位错误点。纪录日志时请
思考:这些日志真的有人看吗?看到这条日志你能作什么?能不能给问题排查带来好处?