在我平时java编程及阅读过的一些技术资料中积累了一些java编程时需要注意的细节,下面我把这些内容分享给大家。
1.尽量使用 String str = “str”的方式来创建字符串。
这样相对于new String("str")可以重复利用已经存在于字符串池中的对象,而且不需要在堆中再创建一个新字符串对象。
2.当需要做多次字符串的连接操作时,用StringBuilder或StringBuffer的append来代替String的“+”操作。
因为创建String对象时,是一次性开辟一段定长空间的char[],如果之后对其做修改,JVM是重新new一个新的String对象(char[]),然后拷贝原有对象到新对象中的。这个过程肯定是影响执行效率及浪费内存的。而StringBuilder默认开辟一个char[16],在修改字符串时是在char数组中添加内容,然后移动下标。当长度超过原有长度后,再开辟一个新的char[].在使用StringBuilder时,如果已预知最后累加后的字符串长度,可以使用StringBuilder(int capacity)构造方法来创建长度为capacity的StringBuffer实例,这样可以避免字符串扩容过程中带来的效率问题及内存浪费。但StringBuilder是不考虑线程安全的,要比线程安全的StringBuffer效率高些。
3. 优先考虑使用静态工厂方法代替构造函数来创建对象。
这样做主要有两点好处,一是每个创建对象的方法都可以有个独特的名字,而构造函数不能这样,这样不利于区分不同的构造函数;二是在每次调用对象的时候,不必非创建一个新对象。这样使得一些非可变类可以使用已经构造好的实例或者把已经构造好的实例缓存起来。在jdk的源码中就有很多使用此方式来实例化一个对象的情况,如Boolean.valueOf(boolean)。如果程序要经常创建相同的对象,并且创建过程代价很高,这样就可以很大的提高性能;
4.合适的时候,请使用单例模式。
使用单例可以减轻加载的负担,缩短加载的时间,提高加载的效率,但并不是所有地方都适用于单例,简单来说,单例主要适用于以下三个方面
第一,控制资源的使用,通过线程同步来控制资源的并发访问
第二,控制实例的产生,以达到节约资源的目的
第三,控制数据共享,在不建立直接关联的条件下,让多个不相关的进程或线程之间实现通信
5.避免使用finalize()方法。
由于GC的工作量很大,可能会引起应用程序暂停,所以再选择使用finalize方法进行资源清理,会导致GC负担更大,程序运行效率更差。
在需要销毁对象的时候可以的让对象=null。这样GC会在合适的时机回收。
6.在计算天数的时候记得考虑闰年二月份有29天。
7.在做十进制小数点的精确运算的时候请使用BigDecimal。
float和double都不能提供完全精确的结果。例如System.out.print(1.03-0.42)的运行结果是输出0.6100000000000001,而且有时候四舍五入也不能解决错误。
8.基本类型优于封装类型。
jdk1.5版本以后每一个基本类型都有一个对应的装箱封装类型,而且有自动装箱和自动拆箱功能。基本类型与封装类型主要有3点区别:一是基本类型只有值,而封装类型有对象的一些功能;二是封装类型可以是null;三是基本类型更加节省内存空间而且创建速度快。但在使用封装类型的时候会容易出现下列问题,一是在作比较的时候,若使用封装类型要避免使用“==”来比较两个数字是否相等。因为虽然他们对应的数值相等,但他们并不是同一个实例,会出现即使值相等,但却不“==”的情况;二是在使用封装类型的时候要考虑,若对象是NULL,则会抛出NullPointerException。而这两种情况是在使用更加节省内存和创建速度更快的的基本类型不会出现的。
9.尽量避免随意使用静态变量。
当某个对象被定义为stataic变量所引用,那么gc通常是不会回收这个对象所占有的内存,如
public class A{
static B b = new B();
}
此时静态变量b的生命周期与A类同步,如果A类不会卸载,那么b对象会常驻内存,直到程序终止。
10.尽量在finally块中释放资源。
程序中使用到的资源应当被释放,以避免资源泄漏。这最好在finally块中去做。不管程序执行的结果如何,finally块总是会执行的,以确保资源的能被释放。
11.尽量避免使用二维数组。
二维数据占用的内存空间比一维数组多得多,大概10倍以上。
12.尽量避免使用split。
除非是必须 的,否则应该避免使用split,split由于支持正则表达式,所以效率比较低,如果是频繁的几十,几百万的调用将会耗费大量资源,如果确实需要频繁的 调用split,可以考虑使用apache的StringUtils.split(string,char),频繁split的可以缓存结果。
13.ArrayList & LinkedList
一个是线性表,一个是链表,一句话,随机查询尽量使用ArrayList,ArrayList优于LinkedList,LinkedList还要移动指针,添加删除的操作LinkedList优于ArrayList,ArrayList还要移动数据,不过这是理论性分析,事实未必如此,重要的是理解好两者者的数据结构,对症下药。
13.尽量使用System.arraycopy ()代替通过来循环复制数组。
System.arraycopy() 要比通过循环来复制数组快的多
14.尽量缓存经常使用的对象。
尽可能将经常使用的对象进行缓存,可以使用数组,或HashMap的容器来进行缓存,但这种方式可能导致系统占用过多的缓存,性能下降,推荐可以使用一些第三方的开源工具,如EhCache,Oscache进行缓存,他们基本都实现了FIFO/FLU等缓存算法。
15.尽量使用局部变量
调用方法时传递的参数以及在调用中创建的临时变量都保存在栈(Stack)中,速度较快。其他变量,如静态变量,实例变量等,都在堆(Heap)中创建,速度较慢。
16.单线程应尽量使用HashMap, ArrayList。
HashTable,Vector等使用了同步机制,降低了性能。
17.尽量合理的创建HashMap。
当你要创建一个比较大的hashMap时,充分利用另一个构造函数public HashMap(int initialCapacity, float loadFactor)避免HashMap多次进行了hash重构,扩容是一件很耗费性能的事,在默认中initialCapacity只有16,而 loadFactor是 0.75,需要多大的容量,你最好能准确的估计你所需要的最佳大小,同样的Hashtable,Vectors也是一样的道理。
18.尽量减少对变量的重复计算。
如
for(int i=0;i<list.size();i++)
应该改为
for(int i=0,len=list.size();i<len;i++)
并且在循环中应该避免使用复杂的表达式,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快。
本文出自 “@夏虫冬草@” 博客,谢绝转载!