读书笔记--编写高质量代码 改善java程序的151个建议(一)基础

读书笔记--编写高质量代码 改善java程序的151个建议(一)基础

不要再常量和变量中出现易混淆的字母

例如在定义long i = 1l时 末尾的l应该使用大写L防止混淆

三元操作符的类型务必一致

例如在i<100?90:100.0时 返回值时float类型 ,三元操作符会类型统一化计算

覆写变长方法也循规蹈矩

例如父类有public void method(int t,int... ints){}方法,子类覆写父类方法:public void method(int t,int[] ints){} 这样子是编译不通过的,int...变长参数在编译后的本质就是int[] 所以覆写失败

警惕自增陷阱

例如一个循环里有i=i++;这样的话 无论循环多少次,i都是初始值,因为i被赋的值是i在自增前的值,自增的是右边i的一个临时变量。

养成良好习惯,先是声明UID

UID是在序列化的时候使用的,是在序列化过程中类的版本号,类在反序列化的时候会把磁盘中的序列化数据中保存的UID和要反序列化的java类中的UID做对比 如果不一致则说明类的版本不一致,也就是类发生过修改。如果默认不声明UID,java会自动添加一个,规则是类名,字段名,方法名的一个复杂计算,总之只要你改过类,UID肯定会发生改变。

break万万不可忘

这个好像是废话,但是还是在提一嘴吧。

避免Instanceof非预期结果

instanceof只能比较对象,不能比较基本类型。

用偶判断不用奇判断

意思是在判断奇数偶数的时候,应该判断不是偶数的为奇数,而不要用不是奇数的是偶数判断。 例如i%2==1?"奇数”:“偶数”,这里如果i是负数,是不正确的。

用整数型类处理货币

当项目中处理货币问题时,应该把货币扩大100直接用整数处理,因为浮点数有不确定性。

不要让类型默默转换

例如用光速计算太阳到地球的距离时,long i = 30100001000608;乍看没问题,可是i值确实负数,应为表达式右边在计算的时候已经超出了整型的范围。应该这样:long i = 30L100001000608

边界问题

和上一个类似,有一个判断:i+600<2000;本意是i的值不能大于1400,可是如果我们让i+600的值刚好超出int整型范围的话,i+600就是一个负数,i就是一个接近整型范围的数,如果是银行系统的话这个bug就会让银行倾家荡产

不要让四舍五入亏了一方

四舍五入默认情况下,如果平均计算的话入的一方会比舍掉的一方多一些。货币方面一定要注意。RoundingMode提供了一些四舍五入的规则可以选择。

谨防包装类型的比较

基本类型在比较时可以直接用==比较,对象比较时需要用equals比较,但是很多时候系统中定义的是Integer,Long等一些包装类型时会忽略,直接用==比较造成bug.大于小于的比较也是一样。

优先使用整型池

虚拟机在启动时会自动初始化-128~127的整型变量,char类型和在此范围内的整型或者Integer对象都是同一个。

优先选择基本类型

例如public void f(long l){} 和public void f(Long l),虚拟机在选择时会优选选择基本类型的方法。如果f(123),会调用f(long l)方法,而不是f(Long l)方法

不要随便设置随即种子

需要random类设置的随机种子相同,那么生成的随机数序列就相同,不论是不是同一对象。

静态变量要先声明,后赋值。

例如,类中的静态变量会先分配内存空间,然后会根据类中的静态代码块和静态变量的先后循序依次执行。

不要重写父类中的静态方法。

如果子类中声明了和父类相同的静态方法,那么在调用时虚拟机会根据实际new出来的对象来调用静态方法,就算new出的对象是赋值给父类也是一样。

构造函数尽量简化

例如代码:

public class Client {
    public static void main(String[] args) {
        Server s = new SimpleServer(1000);
    }
}

//定义一个服务
abstract class Server{
    public final static int DEFAULT_PORT = 40000;
    public Server(){
        //获得子类提供的端口号
        int port = getPort();
        System.out.println("端口号:" + port);
        /*进行监听动作*/
    }   
    //由子类提供端口号,并做可用性检查
    protected abstract int getPort();
}

class SimpleServer extends Server{
    private int port=100;
    //初始化传递一个端口号
    public SimpleServer(int _port){
        port = _port;
    }
    //检查端口号是否有效,无效则使用默认端口,这里使用随机数模拟
    @Override
    protected int getPort() {
        return Math.random() > 0.5?port:DEFAULT_PORT;
    }
}

输出结果不是0就是4000就是不是100。问题在于,子类初始化时会先初始化父类,这时候子类中的port还没有赋值还是0,然而父类的静态变量已经初始化完成(静态变量的初始化在构造方法之前)

不要在构造函数中初始化其他类

public class Client {
    public static void main(String[] args) {
        Son s = new Son();
        s.doSomething();
    }
}

//父类
class Father{
    Father(){
        new Other();
    }
}
//子类
class Son extends Father{
    public void doSomething(){
        System.out.println("Hi,show me something");
    }
}
//相关类
class Other{
    public Other(){
        new Son();
    }
}

这里只是一个简单的例子,真正大型的项目中,问题不是那么容易发现的。为了给自己以后少找麻烦还是尽量避免的好。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值