周末重新整理了一下过往的笔记,发现以前有很多Java相关的经验都用txt或者word记录起来,于是稍微整理了一下全部打包放上网,做个记录也好。
1. 包装类用equals,基础类就用==
结论
Integer用equals,int用 ==
分析
- 基本型和基本型封装型进行“==”运算符的比较,基本型封装型将会自动拆箱变为基本型后再进行比较,因此Integer(0)会自动拆箱为int类型再进行比较。
- 另外两个Integer对象进行“==”比较时,如果有一方的Integer对象是new获得的,返回false,因为比较的是两个对象的地址。
- 两个基本型的封装型进行equals()比较,首先equals()会比较类型,如果类型相同,则继续比较值,如果值也相同,返回true。
- 基本型封装类型调用equals(),但是参数是基本类型,这时候,先会进行自动装箱,基本型转换为其封装类型,若类型不同返回false,
- 若装箱后类型相同,则比较值,如果值相同,则返回true,否则返回false。
2. 正则表达式预编译使用
结论
使用正则表达式的预编译功能,可以有效加快正则匹配速度。Pattern要定义为static final静态变量,以避免执行多次预编译。
分析
private static final Pattern pattern = Pattern.compile(regexRule);
private void func(...) {
Matcher m = pattern.matcher(content);
if (m.matches()) {
...
}
}
3. HashMap初始化大小提高性能
结论
通过设置HashMap的初始化大小能够提高性能。
分析
HashMap当内部维护的哈希表的容量达到75%时,触发rehash。所以初始化容量要设置成num/3x4,而不是num。阿里的java开发手册里也写了这条,而且阿里为了抵消舍入误差,建议初始化容量设置为num/3x4+1。
initialCapacity = expectedSize / 0.75F + 1.0F
具体的应用为
int size = list.size();
double hashSize = size/0.75+1;
Map<Integer, Integer> map = new HashMap<>(hashSize);
4. SimpleDateFormat中Y和y区别
结论
// 关于SimpleDateFormat的正确写法如下
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
分析
y 是Year, Y 表示的是Week year。Week year 意思是当天所在的周属于的年份,一周从周日开始,周六结束,只要本周跨年,那么这周就算入下一年。
5. Mybatis对象嵌套写法
实体中包含实体写法
public class OrderInfoDto {
......
//另一个对象SubOrderDto
private SubOrderDto subOrderDto;
}
在遇到这种情况的时候,Mapper.xml中应该这样写
<resultMap extends="BaseResultCommon" id="BaseResultMap" type="cn.paohe.finance.model.dto.OrderInfoDto">
<id column="ID" jdbcType="BIGINT" property="id"/>
......
<association property="subOrderDto" javaType="cn.paohe.finance.model.dto.SubOrderDto">
<id column="sub_id" jdbcType="BIGINT" property="id"/>
<result column="ORDER_ID" jdbcType="BIGINT" property="orderId"/>
<result column="ORDER_CODE" jdbcType="VARCHAR" property="orderCode"/>
<result column="ORDER_STATEMENT_ID" jdbcType="BIGINT" property="orderStatementId"/>
<result column="SUB_ORDER_CODE" jdbcType="VARCHAR" property="subOrderCode"/>
</association>
</resultMap>
通过association标签将包含的对象也列举在resultMap里面。
实体中包含集合写法
public class ProcurementOrderVo {
......
//含有另一个集合
private List<RemakListVo> remarkList;
}
在遇到这种情况的时候,Mapper.xml中应该这样写
<resultMap id="BaseResultMap" type="cn.paohe.finance.vo.ProcurementOrderVo">
<id column="ID" jdbcType="BIGINT" property="id"/>
......
<collection property="remarkList" ofType="cn.paohe.finance.vo.RemakListVo">
<result column="REMARK" jdbcType="VARCHAR" property="remark"/>
<result column="addUserId_k" jdbcType="BIGINT" property="addUserId"/>
<result column="addUserName" jdbcType="VARCHAR" property="addUserName"/>
<result column="addTime_k" jdbcType="DATE" property="addTime"/>
<result column="oprTime_k" jdbcType="DATE" property="oprTime"/>
<result column="ALIVE_FLAG" jdbcType="VARCHAR" property="aliveFlag"/>
</collection>
</resultMap>
6. 不推荐使用Apache BeanUtils
结论
采用ASM的映射拷贝是最靠谱的一种做法。
分析
当我们开启阿里代码扫描插件时,如果你使用了Apache BeanUtils.copyProperties进行属性拷贝,它会给你一个非常严重的警告。因为,Apache BeanUtils性能较差,可以使用Spring BeanUtils或者Cglib BeanCopier来代替。结果表明,Cglib的BeanCopier的拷贝速度是最快的,即使是百万次的拷贝也只需要 10 毫秒!相比而言,最差的是 Commons 包的 BeanUtils.copyProperties 方法,100 次拷贝测试与表现最好的 Cglib 相差400 倍之多。百万次拷贝更是出现了2600 倍的性能差异!
查看源码,我们会发现 CommonsBeanUtils 主要有以下几个耗时的地方:
除了性能问题之外,在使用 CommonsBeanUtils 时还有其他的坑需要特别小心!
- 包装类默认值在进行属性拷贝时,低版本CommonsBeanUtils 为了解决Date为空的问题会导致为目标对象的原始类型的包装类属性赋予初始值,如Integer属性默认赋值为0,尽管你的来源对象该字段的值为null。这个在我们的包装类属性为null值时有特殊含义的场景,非常容易踩坑!例如搜索条件对象,一般 null 值表示该字段不做限制,而 0 表示该字段的值必须为0。
- 改用其他工具时当我们看到阿里的提示,知道了CommonsBeanUtils的性能问题,想要改用Spring的BeanUtils时,也要特别小心:
org.apache.commons.beanutils.BeanUtils.copyProperties(Object target, Object source);org.springframework.beans.BeanUtils.copyProperties(Object source, Object target);
从方法签名上可以看出,这两个工具类的名称相同,方法名也相同,甚至连参数个数、类型、名称都相同。但是参数的位置是相反的。因此,如果你想更改的时候,千万要记得,将 target 和 source 两个参数也调换过来!