Java中的基本数据类型有8个:byte、short、int、long、float、double、boolean、char
- 用偶判断,不用奇判断
String str = 1%2==1?"奇数":"偶数";
System.out.println("1 是" + str);
str = 2%2==1?"奇数":"偶数";
System.out.println("-2 是" + str);
str = -1%2==1?"奇数":"偶数";
System.out.println("-1 是" + str);
str = -2%2==1?"奇数":"偶数";
System.out.println("-2 是" + str);
运行结果:
1 是奇数
2 是偶数
-1 是偶数
-2 是偶数
-1 是偶数 ???
需要了解Java取余(%)算法,模拟代码如下:
// dividend:被除数 divisor:除数
public static int remainder(int dividend,int divisor){
return dividend - dividend/divisor * divisor
}
当输入-1时,-1 - -1/2*2 = -1 ,结果为-1,不等1
因此,要修改判断是否为偶数:
i%2 == 0?"偶数":"奇数";
- 用整数类型处理货币
对于货币计算推荐
1、使用BigDecimal
2、使用整型(把参与运算的值扩大100倍,并转变为整型,展现的时候再缩小100倍) - 不要让类型默默转换
Java是先运算再进行类型转换的,基本类型转换时,使用主动声明方式,减少不必要的bug - 边界,边界,还是边界
临界测试,校验边界参数 - 不要让四舍五入亏了一方
根据不同的场景,慎重选择不同的舍入模式,以提高项目的精准度,减少算法损失。
BigDecimal
类提供了7种舍入方式:
// 远离0方向舍入,向绝对值最大的方向舍入,只要舍弃位非0即进位
public final static int ROUND_UP = 0;
//趋向0方向舍入,向绝对值最小的方向舍入,所有的位都舍弃,不存在进位情况
public final static int ROUND_DOWN = 1;
//向正无穷方向舍入
//如果是正数,舍入行为类似于ROUND_UP
//如果是负数,舍入行为类似于ROUND_DOWN
public final static int ROUND_CEILING = 2;
//向负无穷方向舍入
//如果是正数,舍入行为类似于ROUND_DOWN
//如果是负数,舍入行为类似于ROUND_UP
public final static int ROUND_FLOOR = 3;
//最近数字舍入(5进) ,经典的四舍五入模式
public final static int ROUND_HALF_UP = 4;
//最近数字舍入(5舍)
public final static int ROUND_HALF_DOWN = 5;
//银行家算法
public final static int ROUND_HALF_EVEN = 6;
//断言请求的操作具有精确的结果,因此不需要舍入。
//如果对获得精确结果的操作指定此舍入模式,则抛ArithmeticException。
public final static int ROUND_UNNECESSARY = 7;
- 提防包装类型的null值
包装类型参与运算时,要做null值校验 - 谨慎包装类型的大小比较
- 优先使用整型池
通过包装类的valueOf生成包装实例可以显著提高空间和时间性能。
static final int low = -128;
static final int high;
static final Integer cache[];
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
cache[]
是IntegerCache
内部类的一个静态数组,容纳-128到127之间的Integer对象(-128,128),即[-127,127]。
通过valueOf产生包装对象时,如果int参数在[-127,127]范围内,直接从整型池中获取,否则再通过new Integer(i)生成包装对象。
29. 优先选择基本类型
f(140);
f(Integer.valueOf(140));
public static void f(long l){
System.out.println("基本类型的方法被调用");
}
public static void f(Long l){
System.out.println("包装类型的方法被调用");
}
运行结果:
基本类型的方法被调用
基本类型的方法被调用
编译通过了,自动装箱有一个很重要的原则:基本类型可以先加宽,再转变成宽类型的包装类型,但不能直接转变成宽类型的包装类型。(这里说的是自动转换)
int i = 140;
f(i);
public static void f(Long l){
System.out.println("包装类型的方法被调用");
}
上面这段代码编译就不会通过
因为i是一个int类型,不能自动转换为Long型;修改成下面的代码就行了。
重申:基本类型优先考虑。
30. 不要随便设置随机种子
在java项目中通常通过Math.random方法或Random类来获得随机数的。
Random r = new Random(100);
System.out.println("第一个随机数:"+r.nextInt());
System.out.println("第二个随机数:"+r.nextInt());
System.out.println("第三个随机数:"+r.nextInt());
输出结果:
第一个随机数:-1193959466
第二个随机数:-1139614796
第三个随机数:837415749
计算机不同输出的随机数不同,但有一点是相同的:在同一台机器上,甭管运行多少次,所打印的随机数都是相同的。也就是第一次运动打印的是这个随机数,第二次运行打印的还是这个随机数。
这是因为产生随机数的种子被固定了,在Java中,随机数的产生取决于种子,随机数和种子之间的关系遵从以下两个规则:
- 种子不同,产生不同的随机数
- 种子相同,即使实例不同也产生相同的随机数
// Random类的默认种子(无参构造方法)
//System.nanoTime(),操作系统读取的纳秒值每次读取的肯定不同,随机数自然也不同了
public Random() {
this(seedUniquifier() ^ System.nanoTime());
}
若非必要,不要设置随机数种子。
《编写高质量代码:改善Java程序的151个建议》