总结Java开发代码质量和细节

  1. 尽量指定类、方法的final修饰符
    带有final修饰符的类是不可派生的。在Java核心API中,有许多应用final的例子,例如java.lang.String,
    整个类都是final的。为类指定final修饰符可以让类不可以被继承,为方法指定final修饰符可以让方法不可以被重写。
    如果指定了一个类为final,则该类所有的方法都是final的。Java编译器会寻找机会内联所有的final方法,
    内联对于提升Java运行效率作用重大,具体参见Java运行期优化。此举能够使性能平均提高50%。

    建议使用final的地方:实体类(不需要被其他类集成的实体类),以及controller,service,dao/mapper层的参数(不需要重新初始化的参数),其他的地方根据情况可以考虑使用

2.尽量减少对变量的重复计算
例如:for (int i = 0; i < list.size(); i++) size为重复计算
替换为:for (int i = 0, length = list.size(); i < length; i++)

3.尽量采用懒加载的策略,即在需要的时候才创建
例如:
String str = “aaa”;
if (i == 1) {
  list.add(str);
}
建议替换为:需要的时候在创建
if (i == 1){
  String str = “aaa”;
  list.add(str);
}

4.慎用异常
异常对性能不利。抛出异常首先要创建一个新的对象,Throwable接口的构造函数调用名为fillInStackTrace()的本地同步方法,
fillInStackTrace()方法检查堆栈,收集调用跟踪信息。
只要有异常被抛出,Java虚拟机就必须调整调用堆栈,因为在处理过程中创建了一个新的对象。
异常只能用于错误处理,不应该用来控制程序流程

5.尽量不要在循环中使用try…catch…,应该把其放在最外层

  1. 循环内不要不断创建对象引用
    例如:
    for (int i = 1; i <= count; i++){
    Object obj = new Object();
    }
    这种做法会导致内存中有count份Object对象引用存在,count很大的话,就耗费内存了,建议为改为:
    Object obj = null;
    for (int i = 0; i <= count; i++){
    obj = new Object();
    }
    这样的话,内存中只有一份Object对象引用,每次new Object()的时候,
    Object对象引用指向不同的Object罢了,但是内存中只有一份,这样就大大节省了内存空间了

  2. 字符串变量和字符串常量equals的时候将字符串常量写在前面

String str = “123”;
if (str.equals(“123”)){

}

建议修改为:

String str = “123”;
if (“123”.equals(str)){

}这么做主要是可以避免空指针异常

  1. 不要对超出范围的基本数据类型做向下强制转型
    public static void main(String[] args){
    long l = 12345678901234L;
    int i = (int)l;
    System.out.println(i);
    }
    我们可能期望得到其中的某几位,但是结果却是:
    1942892530

  2. 公用的集合类中不使用的数据一定要及时remove掉
    如果一个集合类是公用的(也就是说不是方法里面的属性),那么这个集合里面的元素是不会自动释放的,
    因为始终有引用指向它们。
    所以,如果公用集合里面的某些数据不使用而不去remove掉它们,那么将会造成这个公用集合不断增大,使得系统有内存泄露的隐患

  3. 把一个基本数据类型转为字符串,基本数据类型.toString()是最快的方式、String.valueOf(数据)次之、数据+””最慢

  4. 对资源的close()建议分开操作
    比如我:
    try {
    XXX.close();
    YYY.close();
    } catch (Exception e) {}
    建议修改为:
    try {
    XXX.close();
    } catch (Exception e) {}
    try {
    YYY.close();
    } catch (Exception e) {}
    虽然有些麻烦,却能避免资源泄露

11.循环体内不要使用”+”进行字符串拼接,而直接使用StringBuilder或者StringBuffer不断append
假如我有一个方法:
public String appendStr(String oriStr, String… appendStrs) {
for (String appendStr : appendStrs) {
oriStr += appendStr;
}
return oriStr;
}
每次虚拟机碰到”+”这个操作符对字符串进行拼接的时候,会new出一个StringBuilder,然后调用append方法,
最后调用toString()方法转换字符串赋值给oriStr对象,即循环多少次,就会new出多少个StringBuilder()来,这对于内存是一种浪费
Query q = em.createQuery(“SELECT a.id, a.firstName, a.lastName ”

  • “FROM Author a ”
  • “WHERE a.id = :id”);
    在这些情况下,你应该用一个简单的+来连接你的字符串。Java编译器会对此优化并在编译时执行连接。
    所以,在运行时,你的代码将只使用1个String,不需要连接

12.强制:不捕获或者抛出Java类库中定义的继承自RuntimeException的运行时异常类
异常处理效率低,RuntimeException的运行时异常类,其中绝大多数完全可以由程序员来规避,比如:
ArithmeticException 可以通过判断除数是否为空来规;
NullPointerException 可以通过判断对象是否为空来规避;
IndexOutOfBoundsException 可以通过判断数组/字符串长度来规避;
ClassCastException 可以通过 instanceof 关键字来规避;
ConcurrentModificationException 可以使用迭代器来规避

13.尽可能使用基元,即尽量使用基本的数据类型而不是对象

避免任何开销并提高应用程序性能的另一个简便而快速的方法是使用基本类型而不是其包装类。
所以,最好使用int来代替Integer,使用double来代替Double。这允许JVM将值存储在堆栈而不是堆中以减少内存消耗,
并作出更有效的处理

如果没有涉及到做非空的判断的话,尤其是常量,最好是使用基本数据类型,而不是其包装类

14.检查当前日志级别
这个建议应该是显而易见的,但不幸的是,很多程序员在写代码的时候都会大多会忽略它。在你创建调试消息之前,
始终应该首先检查当前日志级别。否则,你可能会创建一个之后会被忽略的日志消息字符串。

两个反面例子。
// don’t do this
log.debug(“User [” + userName + “] called method X with [” + i + “]”);
// or this
log.debug(String.format(“User [%s] called method X with [%d]”, userName, i));

在上面两种情况中,你都将执行创建日志消息所有必需的步骤,在不知道日志框架是否将使用日志消息的前提下。
因此在创建调试消息之前,最好先检查当前的日志级别。
// 应当
if (log.isDebugEnabled()) {
log.debug(“User [” + userName + “] called method X with [” + i + “]”);
}

15、初始化ArrayList或者HashMap等集合的时候时候,建议指定它的初始容量,arrayList默认容量是10,HashMap默认的容量是16,每次插入数据的时候,都会去检查下它的容量是否够用,如果不够的话,会进行扩容,而这个频繁的扩容是比较消耗性能的,或者是说你只放2,3个元素,但是你使用默认的10的话就有点浪费了
List list=new ArrayList<>(15); Map<String,Object> map=new hashMap<>(10);

16、不推荐直接在if条件等地方出现魔法值,例如: if(“0”.equals(type))

17、命名方面: 强制使用驼峰命名法,优先级:英文(不清楚的可以百度翻译,有道词典等) > 拼音,不推荐简写(可读性差,不易维护)

常量方面:static final修饰, 全部大写,以下划线做分割,比如:正确写法DATE_TIME_FORMATTER,错误写法为DATETIMEFORMAT或者dateTimeFormat
具体的方法,细节等可以参考阿里巴巴 Java 开发手册

18、每个方法的代码尽量不要超过80行,如果说超过了80行,可以考虑下是否可以把一些啰嗦的代码封装成一个函数,以保证代码的简洁,因为在一个函数里面写过长的代码,确实会造成可读性差

19、常量方面,对于我们常使用的,是否可以声明成一个常量,static final修饰的,比如一些字段,格式化日期等的常用到的

20、在数据库mapper/dao层,查询尽量以find开头,删除:delete开头,修改:update开头,插入:insert或者save开头,对于一些统计数据,尽量以count开头,已有的部分代码不易修改的我就不说了,希望在写一个新功能的时候能注意下

21、所有的类,函数尽量都加上javadoc注释,说明这个的功能,类上面尽量加上@auther注解,以方便确认是谁写的,如果多个人都修改过这个类,@auther可以加多个,如:
@auther xxx
@auther abc
,针对成员变量,针对常量,实体类等,最好也加上javadoc注释,说明这个类,方法,成员变量的作用,针对接口的实现类的方法,可以不加,只在接口的地方加

22、成员变量或者方法,不要使用//注释,要么就是javadoc注释,实体类的成员变量,dao,service,controller层的方法尽量加上javadoc注释,正确的注释:
/**

  • 名称
    */
    private String name;
    ,错误的注释:
    //名称
    private String name;
    或者 private String name; //名称
    ,不要使用行尾注释,行尾注释的话可读性差

23、关于实体类,建议重写它的toString方法,使用lombok的话,只需要一个@toString注解 ,这样的话到时候如果有个问题,方便我们输出查看它的值

24、在进行多线程的操作时候,尽量使用线程池来进行控制,而不是直接new Thread().start();

25、在使用条件语句的时候,尽量加上{},正确写法:if(“a”.equals(type)){
System.out.println(XXX);
}
,错误写法:if(“a”.equals(type)) System.out.println(XXX),这样写的话会给后期的维护带来不必要的麻烦

26、使用jdk8的java.time包类替代jdk7以及之前的java.util.Date及其相关的日期相关的操作

27、在接口(interface)中,定义常量和函数的时候,不要加public abstract或者public static final修饰符,因为jdk8还有之前的版本,默认就是publci abstract和public static final,以确保接口的简洁性

28、如果需要重写父类的某个方法时候,或者是接口的实现类,最好加上@Override注解,以方便我们易于区分于接口的实现方法和其他方法

29、针对try catch的异常,不要打印出它的堆栈信息, e.printStackTrace(),e.printStackTrace()在信息过多的时候,很可能会导致程序锁死。也不要只是Log.error(e.message()),这样的 话不方便我们排查原因,
建议采用:log.error(Object object,Throwable e),例如log.error(“xxxx出错了”,e);
如果是针对有些时候,这个异常无关后续的处理的情况下,不需要对异常进行抛出,可以输出warning级别的日志.

30、使用Array.toList(数组)来定义一个List的时候,不可以进行它的add和remove操作,Arrays.asList方法返回的ArrayList是继承自AbstractList同时实现
了RandomAccess和Serializable接口,简单来说,Arrays.asList返回的ArrayList是只读的,不可进行add和remove

31、 在使用@Transactional注解的时候,一定要声明回滚的异常类型 rollbackFor=异常类.class

32、日志的输出可以采用lombok包下的@Slf4j,它会生成一个默认的log对象,不用我们再手动创建log对象,get,set,toString方法也推荐使用@data注解,保证代码的简洁

33、不要随便的定义一个对象的实例,如:List a =new ArrayList(15);,关于这块的命名上,一定是要有一定意义的,而不是随随便便的命名
,比如一个user类的集合,你可以是userList,或者是users,被随便命名或者简写一个u.

34、当读取文件时候文件格式,内容等有误的时候,在给前段返回文件内容有误的时候,记得在后端打印下详细的读取文件有误时的异常信息,而不是只是简单的返回了一个文件格式有误啥的,不方便后期的维护.

35、声明数组时候,尽量不要使用二维数组甚至更长的,因为它们的的开销太大,比如 String [][]strings=new String[2][3];这种写法完全可以通过其他的途径来代替

36、针对类里面的静态变量,建议直接通过类来调用/访问,而不是通过实例化后的对象来调用 ,正确的调用方式为:类名.属性名和类名.方法名。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值