前言
常常我们在使用过程中遇到一些不注意的坑,今天就简单罗列一些常见的问题
拆箱出现NPE
如下图,方法中使用基本类型,调用的时候没有判断null,直接传入包装类型,极容易导致拆箱出现NPE
建议:方法入参使用包装类型
诡异的整型cache导致的现象
由于Java中整型如Integer、Short、Long类型存在cache,默认-127~128之间值是返回同一个对象,因此相等,可以通过再jvm启动指定参数-XX:AutoBoxCacheMax=128,修改cache最大值的大小。
建议:数据的比较,如果是包装类型使用equals比较,或者全部转成基本类型使用==
Arrays.asList使用不当,容易出现异常
由于Arrays.asList返回的list属于AbstractList,没有add、remove相关方法,一旦使用则会抛出异常
建议:可以通过将Arrays.asList的结果传入到ArrayList构造器中,如下
List ints = new ArrayList<>(Arrays.asList(1, 2, 3));
对返回List等集合的方法返回的参数进行操作
由于在日常开发中,很多团队对返回集合的方法,要求没有数据,也需要返回一个空的集合,如下
一旦返回空集合,对于使用方,直接使用,可能会出现UnsupportedOperationException。
建议:使用方,不建议对返回的数据直接进行add、remove等操作,应该通过自定义的集合进行操作,如下
List list = getList();
List arrayList = new ArrayList<>();
arrayList.addAll(list);
arrayList.add("1");
List.toArray一不小心就报错
通常对list集合转数组,采用toArray方法,但由于泛型擦除,实际存储为Object数组,因此无法强转,如下
建议:使用toArray指定返回类型,如下
List list = new ArrayList<>(Arrays.asList("a","b","c"));
String[] strings = list.toArray(new String[0]);
集合在for循环中remove
有经验的研发,基本都知道这个问题,在for循环中remove元素,会导致集合的快速失败,抛出异常
建议:使用Iterator来进行remove操作
方法重载,导致方法冲突
如下,由于正常类型匹配,方法重载会正常运行,一旦传入null,即jvm无法知道实际调用的是哪个方法。
实际上,编译期是无法通过的,需要指定null为哪个类型即可。
使用split方法容易出现忽略最后同名
split方法需要注意2点,一个是参数是可以填写正则表达式的,因此对于一些特殊符号需要转义;另外一个就是当最后出现连续的分隔符时,会忽略中间的内容,如下
使用BigDecimal一不注意,也会出现精度问题
BigDecimal在使用的过程中,不要使用double这样的构造器去构建对象,如下图
建议:一律使用BigDecimal的String构造器
使用Executors创建线程,当线程处理过慢,容易OOM
对于Executors创建的线程池,一般要么是最大线程数为Integer.MAX_VALUE,要么是采用无界队列,在高并发的场景下,极易出现OOM
建议:自行通过ThreadPoolExecutor,指定参数,创建线程池
弱引用等类型如果使用不当,gc过后,仍不会销毁
Java当中存在强引用、软引用、弱引用、虚引用,其中软引用是当jvm内存不足时,释放软引用;弱引用是当执行gc的时候,会回收。
例如弱引用如果使用不当,当发生gc的时候,是不会回收的,软引用也是如此,若使用不当,即使OOM了,也不会被回收。
上面的原因是str是一个强引用,因此执行gc的时候,是不会回收弱应用的。
正确的使用方法如下
如果还有其他的场景的坑,欢迎大家留言,谢谢大家!