java lr(0)如何实现移进和规约_Java开发中日常细节处理

28450be80f87ae6f29421a7fa2557599.png

Java规约

1.POJO类中布尔类型的变量,开头都不要加is,否则部分框架解析会引起序列化错误。

反例:boolean isSuccess,它的方法也是isSuccess(),RPC框架再反向解析的时候,以为对应的属性名称是success,导致属性获取不到,进而抛出异常。

2.POJO类中的变量不能以美元符($)开头,否则部分json框架,属性会丢失。

反例:fastjson在解析时会使用属性的get方法,并取得大写以后的字符串当属性key,但是以$开头的是不区分大小写的。所以解析失败,字段丢失。

3.字符串拼接,在不考虑并发的情况下请使用StringBuilder。考虑并发,请使用StringBuffer。

4.避免通过一个类的对象引用访问此类的静态变量或静态方法,无疑增加编译器解析成本,直接用类名来访问即可。

5.不能使用过时的类或方法。(既然提供方认为过时,那必然会提供新的类或方法,我们调用方有义务去考虑新的实现是什么)。

6.Object的equals方法很容易抛出空指针异常,应使用常量或确定有值的对象来调用equals。

7.所有的相同类型的包装类对象之间值的比较,全部使用equals方法比较。

说明:对于Integer var = ? 在-128至127之间赋值,Integer对象是IntegerCache.cache产生,会复用已有对象,这个区间内的Integer值可以直接使用==进行判断,但是这个区间之外的所有数据,都会在堆在产生,并不会复用已有对象。

8.所有的POJO类属性类型必须使用包装数据类型,RPC方法的返回值和参数必须使用包装数据类型,所有的局部变量使用基本类型。

9.构造方法里面禁止加入任何业务逻辑,如果有初始化逻辑,请放在init方法中。

10.禁止在setter和getter方法中添加业务逻辑,增加排查问题的难度。

11.final可以提高程序响应效率,声明成final的情况:不需要重新赋值的变量,包括类属性,局部变量。对象参数前加final,表示不允许修改引用的指向。类方法确定不允许被重写。

12.慎用Object的clone方法来拷贝对象。

说明:对象的clone方法默认是浅拷贝,若想实现深拷贝需要重写clone方法实现属性对象的拷贝。

13.ArrayList的subList结果不可强转成ArrayList,否则会抛出ClassCastException 异常:java.util.RandomAccessSubList cannot be cast to java.util.ArrayList.

说明:subList返回的是ArrayList的内部类SubList,并不是ArrayList,而是ArrayList的一个视图,对于SubList子列表的所有操作最终会反映到原列表上。

14.在subList场景中,高度注意对原集合元素个数的修改,会导致子列表的遍历,增加,删除均产生ConcurrentModificationException异常。

15.不要在foreach循环里进行元素的remove/add操作,remove元素请使用Iterator方式,如果并发操作,需要对Iterator对象加锁。

16.遍历Map集合 KV,应该使用entrySet而不是keySet。

说明:keySet其实遍历了2次,一次是转为Iterator对象,另一次是从HashMap中取出key所对应的value。而entrySet只是遍历了一次就把key和value都放到了entry中,效率更高。如果是JDK8,使用Map.foreach方法。

17.多线程并发处理定时任务时,Timer运行多个TimeTask时,只要其中之一没有捕获抛出的异常,其它任务便会自动终止运行,使用ScheduledExecutorService则没有这个问题。

18.逻辑复杂的业务,判断条件必须提出来单独处理。

正例:boolean existed = (file.open(fileName,"w") != null && (...) || (...));

if(existed){

...

}

反例:if(file.open(fileName,"w") != null && (...) || (...)){

...

}

19.禁止循环体中定义对象,变量,操作数据库,进行不必要的try-catch操作。

20.获取当前毫秒数System.currentTimeMillis(),而不是new Date().getTime();

说明:如果想获取更加精确的纳秒级时间值,用System.nanoTime()。在JDK8中,针对时间等场景,推荐使用Instant类。

21.对于“明确停止使用的代码和配置”,如方法,变量,类,配置文件。动态配置属性等要坚决从程序中清理出去,避免造成过多的垃圾。

22.不要捕获java类库中定义的继承自RuntimeException的运行时异常类,如:IndexOutOfBoundsException,NullPointerException,这类异常由程序员预检查来避免,保证程序健壮性。

正例:if (obj != null ){

...

}

反例:try {

obj.method();

} catch(NullPointerException e){

...

}

23.异常不要用来做流程控制,条件控制,因为异常处理效率比条件分支低。

24.对大段代码进行try-catch,这是不负责任的表现。catch时请分清稳定代码和非稳定代码,稳定代码指的是无论如何不会出错的代码,对于非稳定代码的catch尽可能进行区分异常类型,在做对应的异常处理。

25.捕获异常是为来处理它,不要捕获了却什么都不处理,如果不想处理,请将该异常抛给它的调用者。最外层的业务使用者,必须处理异常,将其转化为用户可以理解的内容,并且将详细的异常信息打印到日志中,相当于保护案发现场。

26.防止空指针,是程序员的基本修养,注意空指针产生的场景:

1)返回类型为包装数据类型,又啃呢个是null,返回int值时注意判空。

反例:public int f(){

//如果为null,自动解箱抛空指针。

return Integer对象;

}

2)数据库的查询结果可能为null。

3)集合里的元素即使 isNotEmpty,取出的数据元素也可能为null。

4)远程调用返回对象,一律要求进行空指针判断。

5)对于Session中获取的数据,建议空指针检查,避免空指针。

6)级联调用obj.getA().getB().getC();一连串调用,易产生空指针。

27.避免出现重复代码。

说明:随意复制和粘贴代码,必然会导致代码的重复,在以后需要修改时,需要修改所有的副本,容易遗漏。必要时抽取公共方法,或者抽取公共类,甚至是公共模块。

28.日志文件必须保存至少15天,因为有些异常具备以周为频次发生的特点,生产环境禁止输出debug'日志。

29.避免重复打印日志,浪费磁盘空间,务必在log4j.xml中设置additivity=false。

正例:<logger name="com.taobao.dubbo.config" additivity="false">

数据库规约

30.合适的字符存储长度,不但节约数据库表空间,节约索引存储,更重要的是提升检索速度。

31.业务上具有唯一特性的字段,即使是组合字段,也必须建成唯一索引。

说明:不要以为唯一索引影响了insert的速度,这个速度损耗可以忽略,但高查找速度是明显的;另外,即使在应用层做了非常完美的校验和控制,只要没有唯一索引,根据墨菲定律,必然有脏数据产生。

32.页面搜索严禁左模糊或者全模糊,如果需要请走搜索引擎来解决。

说明:索引文件具有B-Tree的最左前缀匹配特性,如果左边的值未确定,那么无法使用此索引。

33.创建索引时避免有如下极端误解:

1)误认为一个查询就需要建一个索引。

2)误认为索引会消耗空间,严重拖慢更新和新增速度。

3)误认为唯一索引一律需要在应用层通过“先查后插”方式解决。

34.使用ISNULL()来判断是否为NULL值。注意 NULL与任何值的直接比较都为NULL。

说明:1)NULL <> NULL的返回结果是NULL,而不是false。

2)NULL = NULL的返回结果是NULL,而不是true。

3)NULL <> 1的返回结果是NULL,而不是true。

35.不得使用外键与级联,一切外键概念必须在应用层解决。

说明:(概念解释)学生表中的student_id是主键,那么成绩表中的student_id则为外键。如果更新学生表中的student_id,同时触发成绩表中的student_id更新,则为级联更新。外键与级联更新适用于单机低并发,不适合分布式,高并发集群;级联更新是强阻塞,存在数据库更新风暴的风险;外键影响数据库的插入速度。

36.禁止使用存储过程,存储过程难以调试和扩展,更没有移植性。

37.数据订正时,删除和修改记录时,要先select,避免出现误删,确认无误才能执行更新语句。

ORM规约

38.在表查询中,一律不允许使用*作为查询的字段列表,需要哪些字段必须明确写明。

说明:1)增加查询分析器解析成本。

2)增减字段容易与resultMap配置不一致。

39.不要使用result Class当返回参数,即使所有类属性与数据库字段一一对应,也需要定义;反过来,每一张表也必然有一个与之对应。

说明:配置映射关系,使字段与DO类解藕,方便维护。

40.xml配置中参数注意使用:#{},#param#尽量不要使用${},此种方式容易出现sql注入。

41.iBatis自带的queryForList(String statementName,int start,int size)不推荐使用。

说明:其实现方式是在数据库取到statementName对应的sql语句的所有记录,再通过subList取start,size的子集合,线上因为这个原因曾经出现过内存溢出。

42.禁止直接拿HashMap与HashTable作为查询结果集的输出。

服务器规约

43.高并发服务器建议调小TCP协议的time_wait超时时间。

说明:操作系统默认240秒后,才会关闭处于time_wait状态的连接,在高并发访问下,服务器端会因为处于time_wait的连接数太多,无法建立新的连接,所以需要在服务器上调小此等待值。

正例:在linux服务器上,请通过变更/etc/sysctl.conf文件去修改该缺省值(秒):net.ipv4.tcp_fin_timeout = 30

44.调大服务器所支持的最大文件句柄数(File Descriptor,简写为fd)。

说明:主流操作系统的设计是将TCP/UDP连接采用与文件一样的方式去管理,即一个连接对应于一个fd。主流的linux服务器默认所支持最大的fd数量为1024,当并发连接数很大时,很容易因为fd不足而出现“open too many files”错误,导致新的连接无法连接。建议将linux服务器所支持的最大句柄数调高数倍(与服务器的内存数量相关)

45.给JVM设置-xx:+HeapDumpOnOutOfMemoryError参数,让JVM碰到内存溢出场景时输出dump信息。

说明:内存溢出的发生是有概率的,甚至有规律的相隔数月才出现一例,出现时的现场信息对查错非常有价值。

安全规约

46.用户请求传入的任何参数必须做有效性验证。若忽略参数校验可能导致以下问题:

1)page size 过大导致内存溢出。

2)恶意order by导致数据库慢查询。

3)任意重定向

4)sql注入

5)反序列化注入

6)正则输入源串拒绝服务ReDoS(ReDoS(Regular expression Denial of Service) 正则表达式拒绝服务攻击。开发人员使用了正则表达式来对用户输入的数据进行有效性校验, 当编写校验的正则表达式存在缺陷或者不严谨时, 攻击者可以构造特殊的字符串来大量消耗服务器的系统资源,造成服务器的服务中断或停止。)

47.在使用平台资源,比如短信,邮件,电话,下单,支付,必须实现正确的防重放限制。

说明:如注册时发送验证码到用户手机,如果没有限制次数和频率,那么可以利用此功能骚扰到其他用户,并造成短信平台资源浪费。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值