编写高效优雅安全Java程序的常见原则
面向对象
1 构造器参数太多怎么办?
package hp.domain.constructor; import org.junit.Test; /** * 构造方法参数太多怎么办 * 使用建造者模式,最终是链式的方法 */ public class ConstructorTest { private String name; private String departMent; private int age; private String sex; private float height; private float weight; private String birthAddress; //建造者模式 内部类 private static class innerBuilder { private String name; private String departMent; private int age; private String sex; private float height; private float weight; private String birthAddress; public innerBuilder name(String name) { this.name = name; return this; } public innerBuilder departMent(String departMent) { this.departMent = departMent; return this; } public innerBuilder age(int age) { this.age = age; return this; } public innerBuilder sex(String sex) { this.sex = sex; return this; } public innerBuilder height(float height) { this.height = height; return this; } public innerBuilder weight(float weight) { this.weight = weight; return this; } public innerBuilder birthAddress(String birthAddress) { this.birthAddress = birthAddress; return this; } public ConstructorTest createProduct() { return new ConstructorTest(this); } } /** * 构造函数 * * @param builder */ public ConstructorTest(innerBuilder builder) { this.name = builder.name; this.age = builder.age; this.sex = builder.sex; this.departMent = builder.departMent; this.birthAddress = builder.birthAddress; this.height = builder.height; this.weight = builder.weight; } }
使用builder模式,设计成链式的方法调用
测试
@Test public void test() { //链式的方法调用,生成对象 ConstructorTest constructorInstance = new innerBuilder().age(11).name("小白").sex("男").createProduct(); }
2 不需要实例化的类应该构造器私有
如很多工具类
3 不要创建不必要的对象
尤其注意自动装箱
4 避免使用终结方法
finalize()方法,不确保一定会被执行,被执行的顺序也不确定
5 使类和成员的可访问性最小化
6 使可变性最小化
7 优先使用复合(组合)
除非是真正具有is-a的关系,用继承,否则为了代码的重用都推荐复合,
8 接口优于抽象类
方法
1 可变参数要谨慎使用
对已确定参数,一定不要放到可变参数中,而且可变参数数量可能是0
2 返回零长度的数组或集合,不要返回null
使用 return Collections.emptySet() 集合自带的即可,不返回null集合或数组是个好习惯
3 优先使用标准的异常
通用程序设计
1 用枚举代替int常量
枚举可以自带方法
package hp.domain.enums; /** * 数学计算枚举 */ public enum MathJiSuanEnum { PLUS { @Override int operte(int a, int b) { return a+b; } }, MINUS{ @Override int operte(int a, int b) { return a-b; } }; abstract int operte(int a,int b); }
使用内部枚举策略模式
如我们定义了很多不同的日子,有普通日子,周末,五一,国庆等, 平时加班费2倍,节假日加班费3倍
package hp.domain.enums; /** * 计算加班费 策略模式 * 普通日期 2倍加班费 * 节假日,3倍加班费 五一 周末 国庆 春节 */ public enum EmployeeJiabanEnum { NORMAL(PayCategoryEnum.NORMAL), //周末 WEEKEND(PayCategoryEnum.HOLIDAY), //五一 WUYI(PayCategoryEnum.HOLIDAY), //国庆 GUOQING(PayCategoryEnum.HOLIDAY); private PayCategoryEnum categoryEnum; EmployeeJiabanEnum(PayCategoryEnum categoryEnum) { this.categoryEnum = categoryEnum; } int pay(int workHour) { return categoryEnum.pay(workHour); } /** * 支付策略枚举 */ private enum PayCategoryEnum { NORMAL { @Override int pay(int workHour) { return workHour * normalCost; } }, HOLIDAY { @Override int pay(int workHour) { return workHour * holidayCost; } }; //普通日子的加班费倍数 private static int normalCost = 2; //节假日的加班费倍数 private static int holidayCost = 3; //支付方法 abstract int pay(int workHour); } }
测试
@Test public void test() { int result = EmployeeJiabanEnum.WUYI.pay(10); System.out.println(result); }
2 将局部变量的作用域最小化
3 精确计算,避免使用float和double
会有精度问题,如0.1+0.2 就不等于0.3 而是等于 0.30000000000000004 ,所以金额的精度计算,要用BigDecimal
4 当心字符串连接的性能
字符串拼接特别耗性能,特别是在循环等量级比较大的地方,如记录日志,先判断开关是否记录日志,再拼接记录,避免不必要的字符串连接
5 控制方法的大小
单个方法代码控制在80以下,一方面是因为栈帧太大,一方面代码太多肯定耦合高,也不利于维护