【编程素质】代码及性能优化

1,思路

一般如果性能有问题,一般打印日志,在每一处输出消耗时间,看时间消耗在哪里。
如果是sql性能问题,查看执行计划,看慢在哪里,优化sql。
积硅步,致千里。

2,常用工具

1)StopWatch

除了下面介绍的方法外还有其它方法。以下为笔者习惯用法


import org.springframework.util.StopWatch;

		StopWatch stopWatch = new StopWatch("getSearchResult");
        stopWatch.start("total");

        Thread.sleep(1000);
        System.out.println("sql执行");

        stopWatch.stop();
        stopWatch.start("list合并计算");

        Thread.sleep(1000);
        System.out.println("list合并计算");

        stopWatch.stop();
        log.info("getSearchResult检索性能:{}", stopWatch.prettyPrint());

执行结果:

sql执行
list合并计算
11:11:54.141 [main] INFO com.luo.Adapter - getSearchResult检索性能:StopWatch 'getSearchResult': running time (millis) = 2000
-----------------------------------------
ms     %     Task name
-----------------------------------------
01000  050%  total
01000  050%  list合并计算

3,java编程规范

1)对象及方法

  1. 尽量指定类、方法的final修饰符;
  2. String:用equalsIgnoreCase()替代equals()
  3. Long、Integer等:用equals代替==
  4. 用StringBuffer(多线程)、StringBuilder替代String;
  5. 尽可能使用局部变量
  6. 尽量采用懒加载的策略,即在需要的时候才创建
//不好的示范
String str = "aaa";
if(i == 1) {
	list.add(str);
}
//建议替换为如下:
if(i == 1) {
	String str = "aaa";
	list.add(str);
}

  1. 异常只用于错误处理,不做其它用处。
  2. 当复制大量数据时,使用System.arraycopy()命令;
  3. 常量声明为static final,并以大写命名;
  4. 程序运行过程中避免使用反射
    不建议在程序运行过程中使用,除非万不得已,尤其是频繁使用反射机制,特别是Method的invoke方法,如果确实有必要,一种建议性的做法是将那些需要通过反射加载的类在项目启动的时候通过反射实例化出一个对象并放入内存,用户只关心和对端交互的时候获取最快的响应速度,并不关心对端的项目启动花多久时间。
  5. 不要让public方法中有太多的形参。
    public方法即对外提供的方法,如果给这些方法太多形参的话主要坏处是违反了面向对象的编程思想,Java讲求一切都是对象,太多的形参和面向对象的编程思想并不契合,参数太多势必导致方法调用的出错概率增加。
  6. 把一个基本数据类型转为字符串,基本数据类型.toString()是最快的方式、String.valueOf(数据)次之、数据+""最慢。
  7. 不用魔法数
  8. 用Objects.equals()替代a.equals(b);
  9. 用Integer.valueOf()替代new Integer();
  10. 数字添加下划线以方便阅读;(java7)

2)集合

  1. 必须明确存储最大规格;
  2. 取值前先判空(null和size=0);
  3. 数据获取:List<String> newList = Optional.ofNullable(list).orElse(Lists.newArrayList());
  4. 能用Array就不用ArrayList;
  5. 顺序插入和随机访问比较多的场景使用ArrayList,元素删除和中间插入比较多的场景使用LinkedList;
  6. 使用HashMap、ArrayList,多线程考虑Hashtable、Vector。
  7. 实现RandomAccess接口的集合(比如ArrayList)应当使用最普通的for循环而不是foreach循环来遍历。
    这是JDK推荐给用户的,JDK API对于RandomAccess接口的解释是实现RandomAccess接口用来表明其支持快速随机访问,此接口的主要目的是允许一般的算法更改其行为,从而将其应用到随机或连续访问列表时能提供良好的性能。实际经验表明,实现RandomAccess接口的类实例,假如是随机访问的,使用普通for循环效率将高于使用foreach循环,反过来,如果是顺序访问的,则使用Iterator会效率更高。
//样板代码:可以使用类似如下的代码作判断
if(list instanceof RandomAccess) {
	for(int i = 0; i < list.size(); i++) {}
} else {
	Iterator<?> iterator = list.iterable();
	while(iterator.hasNext()) {iterator.next()}
}

  1. 公用的集合类中不使用的数据一定要及时remove掉

3)循环

  1. 禁止在循环中修改循环控制变量;
  2. 禁止在循环中调用接口、访问数据库;
  3. 循环内不创建引用;
//不好的示范
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罢了,
//但是内存中只有一份,这样就大大节省了内存空间了。

4)控制语句

  1. IF语句必须写ELSE;
  2. SWITCH语句必须写DEFAULT;
  3. for的循环判断 语句写常量;
//性能不好,list.size()会重复调用
for(int i = 0; i < list.size(); i++) {
	...
}
//建议替换为如下:
for(int i = 0, length = list.size(); i < length; i++) {
	...
}
//如上写法在list.size()很大的时候,就减少了很多的消耗。

5)获取资源

  1. 禁止一次性读入文件;
  2. finally里关闭资源;
  3. 尽量避免使用JSONObject与Map;
  4. 及时清除不再需要的会话。
    为了清除不再活动的会话,许多应用服务器都有默认的会话超时时间,一般为30分钟。当应用服务器需要保存更多的会话时,如果内存不足,那么操作系统会把部分数据转移到磁盘,应用服务器也可能根据MRU(最近最频繁使用)算法把部分不活跃的会话转储到磁盘,甚至可能抛出内存不足的异常。如果会话要被转储到磁盘,那么必须要先被序列化,在大规模集群中,对对象进行序列号的代价是很昂贵的。因此,当会话不再需要时,应当及时调用HttpSession的invalidate()方式清楚会话。
  5. 使用带缓冲的输入输出流进行IO操作
    带缓冲的输入输出流,即BufferedReader、BufferedWriter、BufferedInputStream、BufferedOutputStream,这可以极大地提升IO效率。
  6. 对资源的close()建议分开操作
    虽然有些麻烦,却能避免资源泄漏,这其实和try-catch机制相关,各自分开close各自的try-catch就会互不影响,防止写在一个try-catch中因为一个异常了后面的释放不了。

6)线程和同步

  1. 同步块粒度越小越好;
  2. 使用数据库连接池和线程池
    这两个池都是用于重用对象的,前者可以避免频繁的打开和关闭连接,后者可以避免频繁的创建和销毁线程。
  3. 对于ThreadLocal在线程池场景使用前或者使用后一定要先remove。

7)

4,sql规范

  1. SQL中出现数组、jsonb等集合类字段时,须说明最大存储规格,代码中明确存在限制逻辑;
  2. VARCHAR长度为2n-1,不能是2n;
  3. 可重复执行的;
  4. 建表必须有主键、create_time、update_time;

5,rest-api规范

6,原理

1)方法内联

在JVM运行期间的编译优化JIT过程里,会考虑内联方法来提升执行效能。方法内联就是把被调用的函数代码"复制"到调用方函数中!以空间换时间,占用更多的内存,所以JVM更偏好更小的方法。

方法内联的前提:

  1. 方法被final修饰;
  2. 方法小。
    如果方法是经常执行的,默认情况下,方法大小小于325字节的都会进行内联(可以通过 -XX:MaxFreqInlineSize=N 来设置这个大小);
    如果方法不是经常执行的,默认情况下,方法大小小于35字节才会进行内联(可以通过-XX:MaxInlineSize=N 来设置这个大小)。

2)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值