1 整数的绝对值一定是正数?
Integer的取值范围是-231 ~231 - 1,即-2147483648 至 2147483647
当使用abs想要取得Integer.MIN_VALUE即-2147483648的绝对值,正常来讲,结果是2147483648,但2147483648大于了2147483647,即超过了Integer的取值范围,这时候就会发生越界。
虽然这种情况发生的概率很低,只有当要取绝对值的数字是Integer.MIN_VALUE的时候,得到的数字还是个负数。
- 针对取Long.MIN_VALUE的绝对值,结果是负数的原因 和 上面类似。
- 针对取Byte.MIN_VALUE、Short.MIN_VALUE的绝对值时,调用的是public static int abs(int a),将Byte、Short转换为Integer处理,所以没有发生越界,结果为正数
- 针对Double.MIN_VALUE、Float.MIN_VALUE其最小值是一个极小的正数,分别是2-1074、2-149,所以绝对值的结果是正数
System.out.println(Math.abs(Byte.MIN_VALUE));
System.out.println(Math.abs(Short.MIN_VALUE));
System.out.println(Math.abs(Integer.MIN_VALUE));
System.out.println(Math.abs(Long.MIN_VALUE));
System.out.println(Math.abs(Double.MIN_VALUE));
System.out.println(Math.abs(Float.MIN_VALUE));
结果是:
128
32768
-2147483648
-9223372036854775808
4.9E-324
1.4E-45
2 包装类对象之间值的比较需要使用equals
在-128 至 127 范围内的赋值,Integer、Short、Long 对象是在IntegerCache.cache 、ShortCache.cache、LongCache.cache中产生,复用已有对象,这个区间内的值可以直接使用==进行判断,但是这个区间之外的所有数据,都会在堆上产生,并不会复用已有对象,这是一个大坑,推荐使用 equals 方法进行判断。
注意:因为Byte的取值范围是-128 ~ 127, 所以Byte对象的值永远是从ByteCache.cache中产生的,复用已有的对象,可以直接使用==进行判断。
Long c = 2000L;
Long d = 2000L;
System.out.println(c.equals(d));
System.out.println(c==d);
结果是true、false
3 日期YYYY格式设置的坑
YYYY: 当天所在的周属于的年份,一周从周日开始,周六结束,只要本周跨年,那么这周就算入下一年
Calendar calendar = Calendar.getInstance();
calendar.set(2019, Calendar.DECEMBER, 31);
Date testDate = calendar.getTime();
SimpleDateFormat dtf = new SimpleDateFormat("YYYY-MM-dd");
System.out.println("2019-12-31 转 YYYY-MM-dd 格式后 " + dtf.format(testDate));
dtf = new SimpleDateFormat("yyyy-MM-dd");
System.out.println("2019-12-31 转 yyyy-MM-dd 格式后 " + dtf.format(testDate));
结果:
2019-12-31 转 YYYY-MM-dd 格式后 2020-12-31
2019-12-31 转 yyyy-MM-dd 格式后 2019-12-31
4 Arrays.asList 的坑
返回的 List 不支持增删操作
Arrays.asList 返回的是ArrayList是Arrays类中的一个内部类,和java.util.ArrayList不同,
public class ArrayAsListTest {
public static void main(String[] args) {
String[] array = {"1", "2", "3"};
List list = Arrays.asList(array);
list.add("5");
System.out.println(list.size());
}
}
使用Arrays.asLis的时候,对原始数组的修改会影响到我们获得的那个List
public class ArrayAsListTest {
public static void main(String[] args) {
String[] arr = {"1", "2", "3"};
List list = Arrays.asList(arr);
arr[1] = "4";
System.out.println("原始数组"+Arrays.toString(arr));
System.out.println("list数组" + list);
}
}
** 输入参数只能是泛型变长参数**
Arrays.asList方法输入参数只能是一个泛型变长参数。
基本类型是不能泛型化的,即8个基本类型不能作为泛型参数,要想作为泛型参数就必须使用其所对应的包装类型
在Java中,数组是一个对象且是可以泛型化的,例子中把一个int类型的数组作为了T的类型,所以在转换后在List中只有1个类型为int数组的元素了,所以长度是1
int[] intArr = {1,2,3,4,5};
Integer[] integerArr = {1,2,3,4,5};
String[] strArr = {"1", "2", "3", "4", "5"};
List list1 = Arrays.asList(intArr);
List list2 = Arrays.asList(integerArr);
List list3 = Arrays.asList(strArr);
System.out.println("list1中的数量是:" + list1.size());
System.out.println("list2中的数量是:" + list2.size());
System.out.println("list3中的数量是:" + list3.size());
结果如下:
list1中的数量是:1
list2中的数量是:5
list3中的数量是:5
5 金额数值计算精度的坑
结算结果跟我们预期不一致,是因为计算机是以二进制存储数值的,包括浮点数。对于计算机而言,0.1无法精确表达,这就是为什么浮点数会导致精确度缺失的。因此,金额计算时一般都是用BigDecimal 类型。
System.out.println(0.1+0.2);
System.out.println(1.0-0.8);
System.out.println(4.015*100);
System.out.println(123.3/100);
double amount1 = 3.15;
double amount2 = 2.10;
if (amount1 - amount2 == 1.05){
System.out.println("OK");
}
注意:使用 BigDecimal 表示和计算浮点数,必须使用字符串的构造方法来初始化 BigDecimal
System.out.println(new BigDecimal("0.1").add(new BigDecimal("0.2")));
System.out.println(new BigDecimal("1.0").subtract(new BigDecimal("0.8")));
System.out.println(new BigDecimal("4.015").multiply(new BigDecimal("100")));
System.out.println(new BigDecimal("123.3").divide(new BigDecimal("100")));
BigDecimal amount12 = new BigDecimal("3.15");
BigDecimal amount22 = new BigDecimal("2.10");
if (amount12.subtract(amount22).equals(new BigDecimal("1.05"))){
System.out.println("OK");
}
6 java.time.Period的大坑
Period其实只能计算同月的天数、同年的月数,不能计算跨月的天数以及跨年的月数
如下面2个日期跨年、跨月,但计算相关的天数,结果却是2
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate date1 = LocalDate.parse("2020-05-12",formatter );
LocalDate date2 = LocalDate.parse("2021-06-14",formatter);
// 计算日期间隔
int period = Period.between(date1,date2).getDays();
System.out.println(period);
正确的写法
- toEpochDay():将日期转换成Epoch 天,也就是相对于1970-01-01(ISO)开始的天数,和时间戳是一个道理,时间戳是秒数。显然,该方法是有一定的局限性的。
- ChronoUnit:一组标准的日期时间单位。这组单元提供基于单元的访问来操纵日期,时间或日期时间。 这些单元适用于多个日历系统。这是一个最终的、不可变的和线程安全的枚举。
- 推荐使用ChronoUnit
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime date1 = LocalDateTime.parse("2020-05-12 00:00:00",formatter );
LocalDateTime date2 = LocalDateTime.parse("2020-06-14 00:00:00",formatter);
ZoneId zoneId = ZoneId.of("Asia/Shanghai");
ZoneOffset zoneOffset = OffsetDateTime.now(zoneId).getOffset();
long period = date2.toEpochSecond(zoneOffset)-date1.toEpochSecond(zoneOffset);
System.out.println(period);
period = date1.until(date2, ChronoUnit.DAYS);
System.out.println(period);
period = ChronoUnit.HOURS.between(date1, date2);
System.out.println(period);