基础篇——代码优化100条之(1—10)
1、从Map中取key和值
当循环中只需要Map的主键时,迭代keySet()是正确的,但是,当需要主键和取值时,迭代entrySet()才是更高效的做法,比先迭代keySet()后再去get取值性能更加。
package com.zzb.test.admin; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.HashMap; import java.util.Map; /** * 当循环中只需要Map的主键时, * 迭代keySet()是正确的,但是,当需要主键和取值时, * 迭代entrySet()才是更高效的做法,比先迭代keySet()后再去get取值性能更加 * Created by zzb on 2019/12/5 14:11 */ public class TestOne { private static final Logger logger = LoggerFactory.getLogger(TestOne.class); public static void main(String[] args){ Map<String,String> map = new HashMap<>(); map.put("one","1"); map.put("two","2"); map.put("three","3"); map.put("four","4"); map.put("five","5"); //反例 for (String key:map.keySet()) { logger.info("key:{}",key); logger.info("value:{}",map.get(key)); } //正例 for (Map.Entry<String,String> entry:map.entrySet()) { logger.info("key:{}",entry.getKey()); logger.info("value:{}",entry.getValue()); } } }
2、集合判空
使用Collection.size()来检测空逻辑上是没有问题的,但是使用Collection.isEmpty()可以获得更好的性能。后者任何时候实现的时间复杂度都是0(1),而前者有时候实现的事件复杂度可能是0(n),如果需要判断是否为null,使用CollectionUtils
package com.zzb.test.admin; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.util.CollectionUtils; import java.util.ArrayList; import java.util.List; /** * 使用Collection.size()来检测空逻辑上是没有问题的, * 但是使用Collection.isEmpty()可以获得更好的性能。后者任何时候实现的时间复杂度都是0(1), * 而前者有时候实现的事件复杂度可能是0(n) * 如果需要判断是否为null,使用CollectionUtils * Created by zzb on 2019/12/5 14:11 */ public class TestOne { private static final Logger logger = LoggerFactory.getLogger(TestOne.class); public static void main(String[] args){ List<String> list = null; if (CollectionUtils.isEmpty(list)) { logger.info("CollectionUtils空集合"); } list = new ArrayList<>(); if (list.size() == 0) { logger.info("空集合"); } list.add("1"); if (!list.isEmpty()) { logger.info("非空集合"); } } }
3、不要将集合对象传给自己
由于某些方法要求参数在执行期间保持不变,因此将集合传递给自身可能会导致异常行为
package com.zzb.test.admin; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; /** * 由于某些方法要求参数在执行期间保持不变,因此将集合传递给自身可能会导致异常行为 * Created by zzb on 2019/12/5 14:11 */ public class TestOne { private static final Logger logger = LoggerFactory.getLogger(TestOne.class); public static void main(String[] args){ List<String> list = new ArrayList<>(); list.add("1"); list.add("2"); list.add("3"); list.add("4"); list.add("5"); list.add("6"); if (list.containsAll(list)) { logger.info("无意义,list.containsAll(list)总是返回true"); } //性能差,不如list.clear()性能高 list.removeAll(list); // list.clear(); if (list.isEmpty()) { logger.info("移除自己之后"); } } }
4、初始化集合大小
集合也是有大小限制的,每次扩容的时间复杂度很有可能是0(n),所以尽量初始化集合的大小,减少扩容的次数
package com.zzb.test.admin; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; /** * 由于某些方法要求参数在执行期间保持不变,因此将集合传递给自身可能会导致异常行为 * Created by zzb on 2019/12/5 14:11 */ public class TestOne { private static final Logger logger = LoggerFactory.getLogger(TestOne.class); public static void main(String[] args){ String[] strs = new String[]{"1","2","3","4","5","6"}; //反例 List<String> listBad = new ArrayList<>(); for (String str:strs) { listBad.add(str); logger.info("每次添加都要进行扩容"); } //正例 List<String> list = new ArrayList<>(strs.length); for (String str:strs) { listBad.add(str); logger.info("初始化扩容完成,此时添加不需要扩容"); } } }
5、字符串的拼接使用StringBuilder
其实直接拼接字符串,java在编译期会自动进行优化,但是在循环中的字符串拼接,java并不能自动进行优化,所以需要使用StringBuilder进行拼接
package com.zzb.test.admin; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; /** * 字符串的拼接使用StringBuilder * 其实直接拼接字符串,java在编译期会自动进行优化,但是在循环中的字符串拼接, * java并不能自动进行优化,所以需要使用StringBuilder进行拼接 * Created by zzb on 2019/12/5 14:11 */ public class TestOne { private static final Logger logger = LoggerFactory.getLogger(TestOne.class); public static void main(String[] args){ String str = ""; //反例 for (int i=0;i<10;i++) { str += i; } logger.info("循环拼接,java不能在编译期自动优化:{}",str); //正例 String a = "1"; String b = "2"; String c = "3"; String d = a + b + c; logger.info("直接拼接,java在编译期自动优化:{}",d); StringBuilder sb = new StringBuilder(); for (int i=0;i<10;i++) { sb.append(i); } logger.info("使用StringBuilder循环拼接:{}",sb); } }
6、list是否属于数组结构,判断是否可以随机访问
ArrayList是数组结构,数组的随机访问效率更高;LinkedList是链表结构,其随机访问效率较低。
package com.zzb.test.admin; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; import java.util.RandomAccess; /** * list是否属于数组结构,判断是否可以随机访问 * ArrayList是数组结构,数组的随机访问效率更高;LinkedList是链表结构,其随机访问效率较低 * Created by zzb on 2019/12/5 14:11 */ public class TestOne { private static final Logger logger = LoggerFactory.getLogger(TestOne.class); public static void main(String[] args){ List arrayList = new ArrayList(); List linkedList = new LinkedList(); if (arrayList instanceof RandomAccess && !(linkedList instanceof RandomAccess)) { logger.info("数组结构的list实现RandomAccess,链表结构的list未实现RandomAccess"); } } }
7、Set集合中的Set.contains()方法效率更高
List中的contains方法的时间复杂度大多为0(n),而HashSet中contains方法中的时间复杂度为0(1)
package com.zzb.test.admin; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.*; /** * Set集合中的Set.contains()方法效率更高 * List中的contains方法的时间复杂度大多为0(n),而HashSet中contains方法中的时间复杂度为0(1) * Created by zzb on 2019/12/5 14:11 */ public class TestOne { private static final Logger logger = LoggerFactory.getLogger(TestOne.class); public static void main(String[] args){ List list = new ArrayList(); list.add("1"); list.add("2"); list.add("3"); Set set = new HashSet(list); if (list.contains("1")) { logger.info("时间复杂度为0(n):{}",set.contains("1")); } if (set.contains("1")) { logger.info("时间复杂度为0(1):{}",set.contains("1")); } } }
8、长整型常量后添加大写的L
在使用长整型常量时,后面需要添加大写的L
private long val = 1L;
9、定义常量代替魔法值
使用定义可读取的常量来替代魔法值,方便调试。-1,0,1不属于魔法值
package com.zzb.test.admin; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 定义常量代替魔法值 * 使用定义可读取的常量来替代魔法值,方便调试。-1,0,1不属于魔法值 * Created by zzb on 2019/12/5 14:11 */ public class TestOne { private static final int COUNT = 10; private static final Logger logger = LoggerFactory.getLogger(TestOne.class); public static void main(String[] args){ logger.info("定义常量,命名大写:{}",COUNT); } }
10、初始化静态集合
对于集合类型的静态成员变量,不要使用集合实现来赋值,应该使用静态代码块赋值
package com.zzb.test.admin; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.HashMap; import java.util.Map; /** * 初始化静态集合 * 对于集合类型的静态成员变量,不要使用集合实现来赋值,应该使用静态代码块赋值 * Created by zzb on 2019/12/5 14:11 */ public class TestOne { //反例 private static Map<String,String> mapNot = new HashMap<String,String>(){ { put("ad","不使用"); put("adc","静态块赋值"); } }; //正例 private static Map<String,String> mapYes = new HashMap<String,String>(); static{ mapYes.put("ad","使用"); mapYes.put("adc","静态块赋值"); }; private static final Logger logger = LoggerFactory.getLogger(TestOne.class); public static void main(String[] args){ logger.info("集合初始化反例:{}",mapNot); logger.info("集合初始化正例:{}",mapYes); } }