大纲:浮点数据的处理、日期数据的处理、控制语句的避坑规范、优雅的面向对象
浮点数据处理:
在计算机中,用浮点数近似表示任意某个实数,它无法精确表示一个数据,整型数据才可以精确表示一个值。
货币数据类型的选择:任何货币金额均以最小货币单位且整型类型来进行存储。
0.1默认是double类型
浮点数据类型的问题:精度丢失
单精度存储示例:(5.2)
- 首先转换整数部分,即 5 变成二进制101
- 小数部分相当于是2^(-1)一直到2^(-N)的和
![]()
- 乘二取整法:我们可以把十进制的小数部分乘以2,取整数部分作为二进制的一位,剩余小数继续乘以2,直至不存在剩余小数为止。
规格化:5.2转换成二进制即101.00110011001100110011,然后将转换完成的二进制数据规格化,保持小数点前有且只有一个“1”,变成1.0100110011001100110011 * 2^2
指数部分的填充:
补充说明:
精确的小数存储使用decimal
MySQL:decimal(M,D) ------> JAVA: JAVA.math.BigDecimal类
浮点数据避坑:
(一)浮点数之间的等值判断,基本数据类型不能用==来判断,包装数据类型不能用equals来判断
正例:
指定一个误差范围,两个浮点数的差值在此范围内,则认为是相等的
float a = 1.0F - 0.9F
float b = 0.9F - 0.8F
float diff = 1e-6F
if ( Math.abs (a-b)< diff ) { System.out.println("true")}
(二)BigDecimal的等值比较应使用compareTo()方法,而不是equals()方法
equals():方法会比较值和精度(1.0与1.00返回结果为false)
compareTo():会忽略精度
(三)禁止使用构造方法BigDecimal(float)的方式把double值转换为BigDecimal对象
日期数据类型处理
传统日期API的问题:
- 所有日期类型都是线程不安全的
- 日期、时间、时间戳没有明确对应的类,都是Date
- 对于格式化和解析的需求,都是使用SimpleDateFormat类
JDK8新增API的优势:
日期格式化需要注意的问题:
(一)日期格式化时,传入patten中表示年份统一使用小写的y
- 小写yyyy:表示当天所在的年
- 大写YYYY:代表是week in whick year(JDK7之后引入的概念),意思是当天所在的周属于的年份,有可能出现跨年的情况
(二)注意分辨M、m,H、h
- 表示月份是大写的M
- 表示分钟则是小写的m
- 24小时制的是大写的H
- 12小时制的则是小写的h、
(三) 获取当前毫秒数:
System.currentTimeMills();而不是new Date().getTime()
如果想获取更加精确的纳秒级时间值,使用System.nanoTime的方式
在JDK8中,针对统计时间等场景,推荐使用Instant类
控制语句的避坑
控制语句之switch
- 每个case要么通过continue / break / return等来终止
- 要么注释说明程序将继续执行到哪一个case为止
- 在一个switch块内,都必须包含一个default语句并且放到最后
- 当switch括号内的变量类型为String并且此变量为外部参数时,必须先进行null判断
控制语句规约(一)
在 if / else / for / while / do语句中必须使用大括号
表达异常的分支时,少用 if-else方式
if 的嵌套不要超过三层
控制语句规约(二)
在高并发场景中控制语句规约
在高并发场景中,避免使用“等于”判断作为中断或退出的条件,如果并发控制没有处理好,容易产生等值判断被“击穿”的情况,使用大于或小于的区间判断条件来代替
需要参数校验的场合
- 调用频次低的方法
- 执行时间开销很大的方法。此情形中,参数校验时间几乎可以忽略不计,但如果因为参数错误导致中间执行回退,或者错误,那得不偿失
- 需要极高稳定性和可用性的方法
- 对外提供的开放接口,不管是RPC / API / HTTP接口
- 敏感权限入口
- 公开接口需要进行入参保护,尤其是批量执行的接口
不需要参数校验的场合
- 皆有可能被循环调用的方法
- 底层调用频度比较高的方法(比如DAO层的参数校验,可以忽略)
- 被声明成private
OOP(面向对象编程)
面向对象四大特征:抽象、封装、继承、多态
OOP规约:
- 所有的覆写方法,必须加@Override注解
- 尽量不用可变参数。用的话要尽可能保证相同参数类型,相同业务含义,避免使用Object;可变参数必须放置在参数列表的最后;
- 对象的比较:
- 所有整型包装类对象之间值得比较,全部使用equals方法比较
- 应使用常量或确定有值的对象来调用equals,或java.util.Objects#equals(Object a,Object b)
- 方法及属性:
- 所有的POJO类属性必须使用包装数据类型(可以为空;基础数据类型有默认值)
- 定义DO / DTO / VO 等POJO类时,不要设定任何属性默认值
- 定义数据对象DO类时,属性类型要与数据库字段类型相匹配
- getter / setter 方法中,不要增加业务逻辑
- 禁止在POJO类中,同时存在对应属性 xxx 的 isXxx () 和 getXxx () 方法
- 构造方法里面禁止加入任何业务逻辑,如果有初始化逻辑,请放在init方法