避免创建不必要的对象
说明:重用一个已经创建的对象比创建一个新的对象要好得多,除非确实需要重新创建。创建重复不必要的对象会导致资源浪费,严重时可能会导致性能问题。
示例:
不好:
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); }