java 语法层面调优

主要是针对java语法层面的优化


  1. 使用Clone()方式创建对象
    采用clone()方式是直接复制当前对象的所有信息,不会调用对象的构造函数。性能得到提升,但是clone()方法是浅克隆,如果对象中有引用对象,则直接将引用复制。
  2. 避免对boolean进行判断
    如string.endswith(“a”) == true。
    在表达式本身就是boolean值结果的时候,避免比较可以使代码执行更快且更整洁。
  3. 使用三目运算符替换if-else。
if(){

}else{

}

等价于

表达式 ? a : b

好处是代码变短,并且JVM在做代码优化时也是相同的处理。
4. 静态方法替换实例方法
因为实例方法需要维护一张类似虚拟函数导向表的结构,以便实现多态。
静态方法可以通过类名.方法或者对象.方法。
静态方法只能调用静态变量,所以不会改变对象状态。
静态方法可以更快的调用。
5. 使用final关键字
将方法锁定,防止继承类修改。
6. 避免不需要的instanceof操作。
7. 避免子类中存在父类转换
可以直接将子类对象赋值给父类引用,不需要转换。
8. 建议多使用局部变量
局部变量保存在栈里面,读写较快,且回收方便。
静态变量(类变量),静态变量和实例变量都属于全局变量。
9. 运算效率最高的方式——位运算
- >>> 和 >> 的区别:>>>操作数高位补0,>>操作数高位移入原来高位的值。
- 右移一位相当于除以2,左移一位相当于乘以2
- 若进行位逻辑运算的两个操作数的数据长度不一样,则返回值应该是数据长度较长的数据类型。
- 按位异或可以不适用临时变量完成两个值得交换,也可以使某个整型数的特定位的值翻转。
- 按位与运算可以用来屏蔽特定的位,也可以用来取某个整型数的某些特定位。
- 按位或运算可以用来对某个整型数的特定位置为1
10. 用一维数组代替二位数组
二维数组的访问速度优于一维数组,当内存空间却是一维数组的10倍。
11. 布尔运算代替位运算
逻辑或、逻辑与只要条件满足,则可以忽略后续表达式,而位运算则需要计算全部表达式。
在条件判断时,避免使用位运算。
12. 提取表达式优化
例:

for(){
    b1 = a1 * a2 * a3 / 3 * 4 * a3 * a4;
    b1 = a1 * a2 * a4 / 3 * 4 * a4 * a4;
}

提取表达式:

for(){
    combine = a1 * a2 / 3 * 4 * a3 * a4;
    b1 = combine * a3;
    b1 = combine * a4;
}

13.少用取反操作符(!)
取反操作表示异或。使用方便但降低了程序可读性。
14. 不要重复初始化变量
类的成员属性会在调用构造函数时,默认初始化。
当给成员变量设置初始值时,又要调其他方法,最好放在一个方法里面,因为调用某方法赋值可能会因为类尚未初始化而抛出空指针异常。
15. 在switch()中使用字符串进行条件匹配,这个功能是在jdk 1.7才支持。
16. 数值字面量
数字默认为十进制。
八进制在整数字面量前面加0
十六进制在数字前面加0x(0X)
二进制在数字前面加0b(0B), > jdk1.7
为了便于阅读,可以在数字中间加入下划线“_”,不影响使用。但不允许在数字开头及末尾加下划线。
17. 针对基本数据类型的优化
字符串内部化,即字符串常量池,相同的字面量字符串指向同一个对象。
-128~127的short、int、char以及包装类对象指向相同的对象。
18. 空变量
在方法中,局部变量在方法结束时,会自动被编译器赋值null,然后被回收。但是如果在方法中,使用了静态变量,则只要所在类加载在虚拟机中,则变量将一直存在,直到对它进行重新赋值,上一个对象才会被回收。并且如果静态变量占用空间特别大,在eden区不足的时候,可能进行老年代担保直接进入老年代,则该对象被回收的时间则更加延后了。但每次使用后赋值null,则可以保证静态变量被立即回收。
19. List.subList(int fromIndex,int toIndex);返回子集合,但是父集合和子集合的修改都会相互影响。
20. 集合内部避免返回null。
返回null,则在使用时,需要添加判空代码。可以返回空集合或者空数组。Collections.emptyList();注意返回的空集合是不允许被修改的。
21. 判断数组中是否有某个元素。而不需要使用循环遍历。

ArrayList.asList(T[] array).contains(T obj);

22.ArrayList与LinkedList

ArrayList底层采用数组实现,对数据的随机访问比较快,但是在数据的增加或者删除则需要移动大量的元素,越靠前,则消耗越大。并且在容量大小需要扩展时,同样需要复制大量数组。而LinkedList则采用链表的方式实现,对于数据的访问需要通过循环的方式,但是对于添加和删除元素则比较简单。由于内部需要维护Entry对象,则占用空间比较大。
23. Vector和HashTable是线程安全的。ArrayList、HashMap是非线程安全的。Collections.synchronized(List list),返回一个线程安全的同步列表。Collections.synchronized(Map K,V> m);返回一个线程安全的同步HashMap。
24. HashMap底层使用的是链表数组。即每个数组中存放的是链表的头结点。首先,通过对象的hash值,来找到数组下标,然后如果该下标处没有元素,则存放该节点。否则,存放该节点并在节点中引用前一个节点构成链表。获取元素时,如果该下标处有多个节点,则需要循环遍历。
25. HashSet内部通过封装HashMap来完成功能。
26. LinkedHashMap保存元素加入时的顺序。
27. TreeMap则根据key进行排序,排序方式可以由Compartor或Comparable确定。
28. 迭代器
- java 1.2

Iterator i = xxx.iterator();
while(i.hasNext()){
    System.out.println(i.next());
}
  • java 5
for(String item : items){
    System.out.println(temp);
}
  • java 8(lambda表达式)
List<String> lists = new LinkedList<>();
……
lists.forEach(item->System.out.println(item));

29.流
流是应用在一组元素上的一次执行的操作序列。集合和数组都可以用来产生流。
流不存储集合中的元素。
流管道由数据源、若干个中间操作、一个最终操作组成。
中间操作对数据集完成检索、过滤等中间业务。
最终操作完成对数据集的最终处理。
例:完成对长度大于12的单词计数。

List<String> words = new ArrayList();
......
long count = words.stream().filter(w -> w.length() > 12 ).count();

Stream操作符不会改变源对象。
Steam操作符可能是延迟执行的。

并行计算:

List<String> words = new ArrayList();
......
long count = words.parallelStream().filter(w -> w.length() > 12 ).count();

parallelStream自动才用多线程进行并行计算。但执行顺序可能会发生变化


中间操作包括:distinct()、sorted()、map()等。

最终方法包括:forEach()、allMatch()、anyMatch()、findAny()、findFirst()、sum()、max()、min()、averag()等。
30. String对象
String成员变量声明:

private final char value[];
private final int offset;
private final int count;
private int hash;

一个空String所占空间:对象头(8个字节)+ char数组(16个字节)+ 3个int(12个字节) + 一个char数组引用(4个字节) = 40字节
new String(“abc”)会在堆中分配内存,而使用字面量常量,则在常量池中创建。
在用“+”拼接字符串时,会产生中间对象。所以尽量使用StringBuilder。
String对象一旦生成,则不能对它进行改变。
str1.intern() == str2.intern();比较两个字符串是否来自执行一个常量池对象。
substring();方法公用原字符串数组对象,只是改变了偏移量。
31. 用charat()代替startswith();性能比较快
32. 在字符串相加的时候,如果只有一个字符,在使用单引号。
string a = “abc”+’d’;
33. 字符串切割中,性能StringTokenizer > substring() > split();
34. 字符串重编码:

String s = "张三";
String s1 = new String(s.getBytes("UTF-8"),"UTF-8");

35.字符串拼接:StringBuilder > concat() > “+”; “+”表示直接拼接字符串。
36. 强引用:直接引用,可以导致OOM.
37. 软引用:如果内存足够的时候,就保存对象。否则,则回收。通过java.lang.ref.SoftReference使用。
38. 弱引用:通过java.util.WeakHashMap类使用。
39. 幽灵引用:在对象被回收时得到通知,不能通过幽灵引用来获取被引用的对象。
40. try-catch处理多个异常(> 1.7)

try{

}catch(Exception A | Exception B){

}
  1. 避免在循环中调用同步方法,但可以在同步代码块中,循环调用非同步方法。
public synchronized void method(){

}

for(){
    method();
}

改为:
public void method(){};
synchronized{
    for(){
        method();
    }
}

42.当循环嵌套时,应该把次数多的放在内侧。因为需要创建的循环遍历更少。

for(int i = 0; i < 100;i++){
    for(int j = 0 ; j < 100000; j++){
        // 只需要创建100个j变量,反之则需要100000个。
    }
}

43.当判断条件多于2时才考虑switch语句。
44. 减少循环次数

for(int i =0;i<99999;i++){
    a[i] = i;
}

for(int i =0;i<99999;i+=3){
    a[i] = i;
    a[i+1] = i+1;
    a[i+2] = i+2;
}

45.将变量声明在循环体外部
46. 使用System.arraycopy()来进行数组复制。因为底层调用native方法,效率更快。
47. 进行I/O操作的时候,使用缓存流。
OutputStream -> FileOutputStream -> BufferedOutputStream
InputStream -> FileInputStream -> BufferedInputStream
Writer -> FileWriter -> BufferedWriter
Reader -> FileReader -> BufferedReader
48. 在finally中释放或者关闭资源的占用。
49. 不使用中间变量交换数据

a = a + b;
b = a - b;
a = a - b;
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值