避免创建不必要的对象
说明:重用一个已经创建的对象比创建一个新的对象要好得多,除非确实需要重新创建。创建重复不必要的对象会导致资源浪费,严重时可能会导致性能问题。
示例:
不好:
String s = new
String("string");
推荐:
String s = "string";
将对象存入HashSet,或作为key存入HashMap(或HashTable)后,必须确保该对象的hashcode值不变,避免因为hashcode值变化导致不能从集合内删除该对象,进而引起内存泄露的问题
说明:对于Hash集合(HashMap,HashSet等)而言,对象的hashcode至关重要,在hash集合内查找该对象完全依赖此值。如果一个对象存入Hash集合后hashcode随即发生变化,结果就是无法在集合内找到该对象,进而不能删除该对象,最终导致内存泄露。
示例:
错误的示例
public class Email
{
public String address;
public Email(String address)
{
this.address = address;
}
public int hashCode()
{
int result = address.hashCode();
return result;
}
public static void main(String[] args)
{
HashSet<Email> set = new HashSet<Email>();
Email email = new Email("huawei.com");
set.add(email);
email.address = "silong.com"; //修改地址值,导致hashcode值变化 ......
System.out.println(set.contains(email)); //false
set.remove(email); //leak
}
}
执行IO操作时,应该在finally里关闭IO资源
说明:申请的资源不使用时,都要释放。而在产生异常时,资源释放常被忽视。因此要求在数据库操作、IO操作等需要显示使用方法如close()释放资源时,必须在try
-catch-finally的finally中close()。如果有多个IO对象需要close(),需要分别对每个对象的close()方法进行try-catch,防止一个IO对象关闭失败其他IO对象都未关闭。保证产生异常时释放已申请的资源。
示例:
try
{
in = new FileInputStream(inputFileName);
out = new FileOutputStream(outputFileName);
copy(in, out);
}
finally
{
close(in);
close(out);
}
public static void close(Closeable c)
{
if (c == null)
return;
try
{
c.close();
}
catch (IOException e)
{
// log the exception
}
}
消除过期的对象引用
说明:过期引用是指永远也不会再被解除的引用。在支持垃圾回收的语言中,内存泄露是很隐蔽的。如果一个对象引用被无意识地保留起来,
那么,垃圾回收机制不仅不会处理这个对象,而且也不会处理被这个对象所引用的所有其他对象。
例如:如下是Stack类的pop方法。被弹出的对象,不会被垃圾回收机制回收,即使使用Stack的程序不再引用被弹出的对象,也不会回收。因为,Stack内部仍维护着对这些对象的过期引用。
public Object pop()
{
if (size == 0)
{
throw new EmptyStackException();
}
return elements[--size];
}
改为如下,则可消除过期引用
public Object pop()
{
if (size == 0)
{
throw new EmptyStackException();
}
Object result = elements[--size];
elements[size] = null;
return result;
}
性能与资源管理
谨慎地进行性能优化说明:优化的弊大于利,特别是不成熟的优化。在优化的过程中,产生的软件可能既不快速,也不正确,而且还不容易修正。不要因为性能而牺牲合理的结构。要努力编写好的程序而不是快的程序。如果好的程序不够快,它的良好结构可以是它可以得到更加便利的优化。好的程序体现了信息隐藏(information hiding)的原则:只要有可能,它们就会把设计决策集中在单个模块中,因此,可以改变单个决策,而不会影响到系统的其他部分。
这并不意味着,在完成程序之前就可以忽略性能问题。实现上的问题可以通过后期的优化而得到修正。但是,遍布全局并且限制性能的结构缺陷几乎是不可能被改正的,除非重新系统。在系统完成之后再改变设计的某个基本方法,会导致系统的结构很不好,从而难以维护和改进。因此,必须在设计过程中考虑的性能问题
使用System.arraycopy()进行数组复制说明:在将一个数组对象复制成另外一个数组对象时,请不要自己使用循环复制,可以使用JAVA提供的System.arraycopy()功能来复制数据对象,这样做可以避免出错,而且效率会更高。
示例:
不好
int[] src = { 1, 2, 3, 4, 5 };
int[] dest = new int[5];
for (int i = 0; i < 5; i++)
{
dest[i] = src[i];
}
推荐
int[] src = { 1, 2, 3, 4, 5 };
int[] dest = new int[5];
System.arraycopy(src, 0, dest, 0, 5);
使用集合的toArray()方法将集合转为数组(v1.42+)
说明:更好的性能,代码更加简洁示例:
ArrayList list = new ArrayList();
list.add....
String [] array = new String[list.size()];
list.toArray(array);
在Java的IO操作中,尽量使用带缓冲的实现
说明:在Java的IO操作,读写操作都有两套实现,一套是没有实现缓冲的,一套是实现了内容缓冲的,使用带有缓冲功能的IO操作,可以降低存储介质的访问次数,从而提高数据读写的效率,提供更好的操作性能。
因此,建议使用带有缓冲功能的实现来进行IO操作。
对于性能要求更高的实现,可以使用Java NIO
示例:
不好
PrintWriter out = null;
try
{
out = new PrintWriter("file.txt");
String line = null;
for (int i = 0; i < 100; i++)
{
// write content
out.println("write content " + i);
}
}
finally
{
IOUtils.close(out);
}
推荐
PrintWriter out = null;
try
{
out = new PrintWriter(new BufferedWriter(new FileWriter("file.txt")));
String line = null;
for (int i = 0; i < 100; i++)
{
// write content
out.println("write content " + i);
}
}
finally
{
IOUtils.close(out);
}