java代码编写优化(持续更新...)

1:使用final修饰方法与属性
被final声明的方法与属性会被jvm缓存与优化,在编译期就关联进来,用于:参数,方法,类,常量(结合static)
final意味不可改变(不可改变的数据那么jvm是不是可以进行缓存)
static意味全局唯一(全局唯一那么是不是内存空间只此一份)

2:StringBuilder/StringBuffer代替String
3:及时关闭流:数据库连接,io,file,redis等
4:尽量减少对变量的重复计算,如重复计算则新建一个变量

1for (int i = 0; i < list.size(); i++){...}
2//替换为
3for (int i = 0, length = list.size(); i < length; i++){...}

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

1for (val = 0; val < 100000; val += 5){
2  a = val * 8;
3  b = val / 2;
4}

用移位操作可以极大地提高性能,因为在计算机底层,对位的操作是最方便、最快的,因此建议修改为:

1for (val = 0; val < 100000; val += 5){
2  a = val << 3;
3  b = val >> 1;
4}

移位操作虽然快,但是可能会使代码不太好理解,因此最好加上相应的注释。

8:循环内不要不断创建对象引用
例如:

1for (int i = 1; i <= count; i++){
2    Object obj = new Object();    
3}

这种做法会导致内存中有count份Object对象引用存在,count很大的话,就耗费内存了,建议为改为:

1Object obj = null;
2for (int i = 0; i <= count; i++){
3    obj = new Object();
4}

这样的话,内存中只有一份Object对象引用,每次new Object()的时候,Object对象引用指向不同的Object罢了,但是内存中只有一份,这样就大大节省了内存空间了。
9:基于效率和类型检查的考虑,应该尽可能使用array,无法确定数组大小时才使用ArrayList

10:尽量使用HashMap、ArrayList、StringBuilder,除非线程安全需要,否则不推荐使用Hashtable、Vector、StringBuffer,后三者由于使用同步机制而导致了性能开销
正常我们写代码的时候不直接用后面三个自带锁的,而是自己在代码块上加锁,然后再使用前面三个

11:使用数据库连接池和线程池
这两个池都是用于重用对象的,前者可以避免频繁地打开和关闭连接,后者可以避免频繁地创建和销毁线程

12:对比小技巧
字符串对比写法:"123".equals(str);
null判断写法:null==str;
变量怕判断:1==num;
这么做主要是可以避免空指针异常与忘记写双等号

扫描二维码关注公众号,回复: 1780159 查看本文章

13:不要对超出范围的基本数据类型做向下强制转型

1long l = 12345678901234L;
2int i = (int)l;
3System.out.println(i);

14:把一个基本数据类型转为字符串,基本数据类型.toString()是最快的方式、String.valueOf(数据)次之、数据+""最慢
String.valueOf()方法底层调用了Integer.toString()方法,但是会在调用前做空判断
Integer.toString()方法就不说了,直接调用了
i + ""底层使用了StringBuilder实现,先用append方法拼接,再用toString()方法获取字符串

15:使用最有效率的方式去遍历Map
遍历Map的方式有很多,通常场景下我们需要的是遍历Map中的Key和Value,那么推荐使用的、效率最高的方式是:

 1public static void main(String[] args){
 2    HashMap<String, String> hm = new HashMap<String, String>();
 3    hm.put("111", "222");
 4    Set<Map.Entry<String, String>> entrySet = hm.entrySet();
 5    Iterator<Map.Entry<String, String>> iter = entrySet.iterator();
 6    while (iter.hasNext()) {
 7        Map.Entry<String, String> entry = iter.next();
 8        System.out.println(entry.getKey() + "\t" + entry.getValue());
 9    }
10}

如果你只是想遍历一下这个Map的key值,那用"Set keySet = hm.keySet();"会比较合适一些

16:对于ThreadLocal使用前或者使用后一定要先remove
如果你在项目中使用到了ThreadLocal,一定要记得使用前或者使用后remove一下。这是因为上面提到了线程池技术做的是一个线程重用,这意味着代码运行过程中,一条线程使用完毕,并不会被销毁而是等待下一次的使用。
线程不销毁意味着上条线程set的ThreadLocal.ThreadLocalMap中的数据依然存在,那么在下一条线程重用这个Thread的时候,很可能get到的是上条线程set的数据而不是自己想要的内容。

17:避免Random实例被多线程使用,虽然共享该实例是线程安全的,但会因竞争同一seed 导致的性能下降,JDK7之后,可以使用ThreadLocalRandom来获取随机数

18:尽量使用栈变量。
调用方法时传递的参数以及在调用中创建的临时变量都保存在栈(Stack)中,速度较快。
静态变量,实例变量等,都在堆(Heap)中创建,速度较慢。

1//存储在堆上
2Integer i = 817598;
3// 存储在栈上
4int i = 817598;
5在使用数组时情况可能会变得更加糟糕:
6//在堆上生成了三个对象
7Integer[] i = { 1337, 424242 };
8// 仅在堆上生成了一个对象
9int[] i = { 1337, 424242 };

猜你喜欢

转载自blog.csdn.net/charjay_lin/article/details/80210578