改善java程序的151个建议--笔记一

一、Java开发中通用的方法和准则

1、不要在常量和变量中出现易混淆的字母

eglong i=1l,这是11还是lL呢,建议使用大写的方式;

2、不要让常量变成变量

egpublic static final int RAND_CONST=new Random().nextInt();

3、三元符的类型务必一致

egString s=String.valueOf(i<100?90:100.0);

4、避免带有变长参数的方法重载

eg:calPrice(int price,int discount);

   calPrice(int price,int... discounts);

5、别让null值和空值威胁到变长方法

egmethodA(String str,Integer... is);

methodA(String str,String... strs);

Test:methodA(“China”);

    methodA(“China”,null);

6、覆写变长方法也要循规蹈矩

Eg:parent:method(int price,int... discounts);

   Children:method(int price,int[] discounts);

7、警惕自增陷阱

Eg:int count=0;for(int i=0;i<10;i++){count=count++};输出结果为0

8、不要让就语法困扰

Eggoto语句、methodA:methodB();

9、少用静态导入

10、不要在本类中覆盖静态导入的变量和方法

11、养成良好的习惯,显式声明UID

Eg:序列化

12、避免用序列化类在构造函数中为不变量(final修饰)赋值

13、避免为final变量复杂赋值

Egpublic final String name=initName();

Public String initName(){return “hello”;}

反序列化时final变量在以下情况下不会被重新赋值:

1)通过构造函数为final变量赋值;

2)通过方法返回值为final变量赋值;

3)Final修饰的属性不是基本类型;

14、使用序列化类的私有方法巧妙解决部分属性持久化问题

15、Break万万不可忘

Switch....case....

16、易变业务使用脚本语言编写

例如通过java中的ScriptEngine调用javascript中的方法

17、慎用动态编译:在运行期间直接编译.java文件,执行.class,将java类信息写入到字符串中,然后运行期间调用相关接口执行字符串中的java信息

18、避免instanceOf非预期结果,注意instanceOf成立的条件是操作数左右两边要有继承或者实现关系,否则编译会报错

Eg:’A’ instanceOf Characternew Date() instanceOf String,

19、断言绝对不是鸡肋:assert<布尔表达式>:<错误信息>

20、不要只替换一个类:发布应用系统时禁止使用类文件替换方式,整体war包发布才是完全之策

二、基本类型

21、判断奇偶数,用偶判断,不用奇判断

Egi%2==1?”奇数”:”偶数”;-1的时候会出现问题

正确使用:i%2==0?”偶数”:”奇数”;

22、用BigDecimal和整形类型处理货币

23、不要让类型默默转换

Eg:public static final int LENGTH_SPEED=30*10000*1000;

   long v=LENGTH_SPEED*60*8会出现负数,因为计算的时候,先是运算再进行类型转换的,三个数都是int类型,计算后超出int的最大值,所以计算结果为负值;

正确的方式:long v=1L*LENGTH_SPEED*60*8;计算的时候后面的都会转换成为长整形

24、整形类型的边界值需要考虑,在进行单元测试的时候,进行int类型参数测试的时候,需要考虑下面几个值:0、正最大、负最小

25、不要让四舍五入亏了一方,例如在做银行、金融相关行业的系统的时候,要根据不同的场景,慎重选择不同的舍入模式,以提高项目的精准度,减少算法损失

26、提防包装类型的null值:包装类型参与运算时候,要做null值校验

27、谨慎包装类型的大小比较

Eg:Integer a=new Integer(100);

   Integer b=new Integer(100);

   a==b:false,a>b:false,a<b:false;

28、优先使用整形池:基本类型的装箱动作是通过valueOf方法来实现的,对于int类型转换为Integer对象,如果int值的范围在-128127之间,那么它直接从cache数组中获得,不在该范围的int类型则通过new生成包装对象,通过包装类的valueOf生成包装实例可以显著提高空间和时间性能

29、优先选择基本类型

Egint i=0;

test(i);

test(Integer.valueOf(i));

public static void test(long i){}

public static void test(Long i){}

在进行自动装箱的过程中,基本类型可以先加宽,再转变成宽类型的包装类型,但是不能直接转变成宽类型的包装类型。Int可以加宽变成long类型,然后再转变成为Long对象,但是不能直接变成Long对象。

30、不要随便设置随机数的种子

Eg:Random random=new Random(1000);产生随机数的种子被固定了

Java中产生随机数:RandomMath.random();

三、类对象及方法

31、在接口中不要存在实现的代码

Interface S{public void doSomething();} interface B{S s=new S(){public void dos{}}}

32、静态变量一定要先声明后赋值

Egstatic{i=100;} public static int i=1;

33、不要覆写静态方法,当父类中定义了一个静态方法后,子类中应不要覆写静态方法,类中定义静态方法或属性应该通过类名直接访问,通过实例对象访问静态方法或属性不是好的习惯;

34、构造函数应尽量简化,否则可能会出现因初始化的时候变量的不一致;

35、避免在构造函数中初始化其他类

36、使用构造代码块精炼程序:构造代码块会在每个不同参数的构造方法中都执行一次,先执行构造代码块,再执行构造方法,它并不是在构造函数之前运行的,它依托于构造函数执行,我们可以把构造代码块运用到如下场景中:1:初始化实例变量2:初始化实例环境;

37、构造代码块会想你所想,在构造方法中使用thissuper的时候,构造代码块已经替你考虑好了,如果在有参数构造方法中使用this(),是不会再重新执行构造代码块的,所以要灵活运用;

38、使用静态内部类加强类的封装性和提高了代码的可读性

39、使用匿名类的构造函数:new ArrayList(){};new ArrayList(){{}{}{}}

40、匿名类的构造函数很特殊;

41、灵活使用内部类,让多重继承成为现实;

42、让工具类不可实例化最好的方式是:这样也不能利用反射机制进行实例化

public class Utils{

private Utils(){

 Throws new Error(“don’t intstance me!!”);

}}

43、避免对象的浅拷贝:

Object提供的clone方法只是一种浅拷贝方式,也就是说它并不会把对象的所有属性全部拷贝一份,而是有选择性的拷贝,其拷贝规则如下:

基本类型:则拷贝其值

对象:拷贝地址引用,也就是说新拷贝出的对象与原有对象共享该实例变量,不受访问权限的限制。

String字符串:拷贝的也是一个地址,是个引用,但是在修改时,它会从字符串池(String pool)中重新生成新的字符串,原有的字符串对象保持不变,在此我们可以认为String是一个基本类型。

44、推荐使用序列化的方式实现对象的拷贝:参考我的博文,java对象的浅拷贝和深拷贝:http://blog.csdn.net/harderxin/article/details/41694747

45、覆写equals方法时不要识别不出自己(见代码)

//	public boolean equals(Object obj) {
//		if(obj instanceof Person3){
//			Person3 p=(Person3)obj;
	//去掉trim()
//			return name.equalsIgnoreCase(p.getName().trim());
//		}
//		return false;
//	}

46、equals应该考虑null值情景

//  第二个版本----建议46
//	@Override
//	public boolean equals(Object obj) {
//		if(obj instanceof Person3){
//			Person3 p=(Person3)obj;
//			if(p.getName()==null||name==null){
//				return false;
//			}else{
//				return name.equalsIgnoreCase(p.getName().trim());
//			}
//		}
//		return false;
//	}

47、为了防止继承,建议在equals中使用getClass进行类型判断,而不是使用instanceOf

//  第三个版本----建议47
	@Override
	public boolean equals(Object obj) {
		if(obj!=null&&obj.getClass()==this.getClass()){
			Person3 p=(Person3)obj;
			if(p.getName()==null||name==null){
				return false;
			}else{
				return name.equalsIgnoreCase(p.getName().trim());
			}
		}
		return false;
	}
	

48、覆写equals方法必须覆写hashcode方法:

     HashMap:底层处理机制是以数组的方式保存Map条目(Map Entry)的,这其中的关键是这个数组下标的处理机制:依据传入元素hashCode方法的返回值决定其数组的下标,如果该数组位置上已经有了Map条目,且与传入的键值相等则不处理,若不相等则覆盖;如果数组位置没有条目,则插入,并加入到Map条目的链表中,同理,检查键是否存在也是根据哈希码确定位置,然后遍历查找键值的。HashCode的值我们可以使用org.apache.commons.lang.builder包下的一个哈希码生成工具HashCodeBuilder生成

49、推荐覆写toString方法:java提供默认的toString方法不友好,打印出来只有机器能看懂,其格式为类名+@+hashCode,所以建议覆写toString方法,便于我们进行调试

50、使用package-info类为包服务:在需要用到包的地方,可以考虑一下这个特殊的类

51、不要主动进行垃圾回收:在应用程序中不要直接使用System.gc()来主动对垃圾进行回收,即使经常出现内存溢出也不要调用

你可能感兴趣的:(改善java程序的151个建议--笔记一)