在我们日常开发中,代码有很多细节都是我们不曾注意的,比如金额应该使用 double 还是 float,或者是int;时间格式化里的yyyy代表什么,使用 大写YYYY 行不行。很多东西我们一直都是看前人这么写的,我们就跟着写,没考虑过为什么。今天,跟着无尘老师我们一下学习一下代码中一些常见的坑。
浮点数据处理浮点型:double、float
浮点数是属于有理数中某特定子集的数字表示,在计算机中用以近似表示任意某个实数
整型:int
计算机中的一个基本的专业术语指没有小数部分的数据
应用场景:
货币数据类型的选择:最小货币单位且整型进行存储
浮点数据类型的问题:精度丢失
浮点数使用科学计数法存储
单精度数存储格式:float
浮点数在计算机的存储: 5.2
整数部分:先将整数部分改写成二进制
5 => 101
小数部分:是 2 的负一次方一直到 2 的负n次方和
0.2在十进制转二进制的时候,是一个无限不循环的二进制数,所以十进制在转二进制的时候会丢失精度
二进制转换后:
101.00110011001100110011
保持小数点前面有且只有一个1
1.0100110011001100110011
最终结果:
有效数字填充:整数部分的1舍去,也就是
01001100110011001100110
指数部分填充
- 在符号位右侧分配8位来存储指数
- 阶码位存储的是指数对应的移码,是将一个真值在数轴上正向平移一个偏移量之后得到的
- 移码的意义是把真值映射到一个正数域,可以直观地反应两个真值的大小,即移码大的真值也大
移码公式:
其中2 的n-1 次方 减1 是IEEE754标准规定的偏移量
在float中的n为8,x移 = x + 127 = 129,二进制为 1000 0001
精确的小数存储-decimal (M,D)
M:指定小数点左边和右边可以存储的十进制数字的最大个数,MySQL中的范围 1~65
D:指定小数点右边可以存储的十进制数字的最大个数。小数数位必须小于M,默认的小数位数为0
Java:java.math.BigDecimal 类
浮点数据避坑:
- 浮点数之间的等值判断,基本数据类型不能用 == 来比较,包装数据类型不能使用 equals 来判断
- BigDecimal的等值比较应使用 compareTo() 方法,而不是equals() 方法
- equals() 方法会比较值和精度(1.0 和 1.00 比较会返回false),compareTo会忽略精度
- 禁止使用构造方法 BigDecimal(double) 的方式把 double 值转化为 BigDecimal对象
Java中传统日期API
Date:表示特定瞬间,精确到毫秒
SimpleDateFormat:继承DateFormat类,主要用来格式转化
Calendar:一个工具类,为特定瞬间和一组日历字段之间的转换以及 *** 作日历字段提供了方法
Java 8新增日期API
LocalDate:代表日期
LocalTime:代表时刻
LocalDateTime:代表具体时间
Instant:代表时间戳
传统API 问题
- 所有日期类都是线程不安全的
- 日期、时间、时间戳没有明确对应的类
- 对于格式化和解析的需求
JDK8 新增API的优势
- 不变性:线程安全
- 关注点分离:时间日期都有对应的类
- 清晰:在所有的类中,方法都被明确定义用以完成相同的行为
- 实用 *** 作:所有新的日期/时间API类都实现了一系列方法用以完成通用的任务
日期格式化需要注意的问题
- yyyy 表示当天所在的年
- YYYY 表示当前周所在的年,如果本周跨年,返回的YYYY就是下一年
- M 月份
- m 分钟
- H 24小时制
- h 12小时制
- 获取当前毫秒数,使用System.currentTimeMillis() ,而不是 new Date().getTime()
控制语句避坑规范
Switch
- 每个case要么通过 continue、break、return 等终止
- 要么注释说明程序将继续执行到哪个case为止
- 在一个Switch 块内,都必须包含一个default语句并放到最后
- Switch 括号内的变量类型为String 并且为外部参数时,必须先进行null判断
三目运算符高度注意类型对齐时,可能抛出因自动拆箱导致的NPE异常
触发场景
- 表达式 1 或表达式 2 的值只要有一个是原始类型
- 表达式 1 和 表达式 2 的值类型不一致,会强制拆箱升级成表示范围更大的那个类型
int a = 1; Integer b = 2; Integer c = null; Boolean flag = false; // a * b 结果是 int类型,那么c会强制拆箱成int类型,抛出NPE Integer result = (flag ? a * b : c)
- 不要在其它表达式中,插入赋值语句,比如条件表达式,因为很容易忽略这个值已经改变
- 不要在条件判断中执行其它复杂的语句,以提高可读性
- 避免采用取反逻辑运算符
高并发场景中的语句规约
在高并发场景中,避免使用 “等于” 判断作为中断或退出条件,如果并发控制没有处理好,容易产生等值判断被击穿的情况,使用大于小于的区间判断条件
需要参数校验的场合
- 调用频次低的方法
- 执行时间开销很大的方法
- 需要极高稳定性和可用性的方法
- 对外提供的开放接口,不管是 RPC/AP/HTTP 接口
- 敏感权限入口
- 公开接口需要进行入参保护,尤其是批量 *** 作的接口
不需要参数校验的方法
- 极有可能被循环调用的方法
- 底层调用频率比较高的方法
- 被声明成 private
种树的最好时间是十年前,其次是现在!
参考文档:无尘老师PPT
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)