孤尽训练营打卡日记day16--Java代码避坑指南

前言

        在我们日常开发中,代码有很多细节都是我们不曾注意的,比如金额应该使用 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

猜你喜欢

转载自blog.csdn.net/qq_35056844/article/details/121258599