【Java资源管理】编程规范每日一学--20130916

避免创建不必要的对象


说明:重用一个已经创建的对象比创建一个新的对象要好得多,除非确实需要重新创建。创建重复不必要的对象会导致资源浪费,严重时可能会导致性能问题。
示例:

不好:

String s = new
String("string");



推荐:

String s = "string";

将对象存入HashSet,或作为key存入HashMap(HashTable)后,必须确保该对象的hashcode值不变,避免因为hashcode值变化导致不能从集合内删除该对象,进而引起内存泄露的问题

说明:对于Hash集合(HashMapHashSet)而言,对象的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
finallyclose()。如果有多个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); 
}