7曾沈、拋棄廢棄的對象引用
當一個對象不再使用時伐蒂,應該將該引用設置為null,避免該對象并不能被JVM回收量淌。文中列出以下幾種情況:
- 數(shù)組中的對象,使用結束后要把對應的未知的引用設置為null嫌褪;
- 注意緩存對象的存活時間呀枢;
- 注意listener和callback的添加和移除;
8渔扎、避免使用FINALIZERS和CLEANERS
Java為對象提供了finalize方法硫狞,當對象被準備回收時調(diào)用,在Java 9之后廢棄finalize晃痴,使用Cleaner残吩,但是兩者都是不推薦使用的。 Java提供了便捷的內(nèi)存回收算法倘核,如果重寫了finalize泣侮,可能導致GC無法回收足夠的內(nèi)存空間,增加OutOfMemoryError的幾率紧唱,也增加了GC的工作時長活尊,所以我們不應該在finalize或者cleaner中嘗試修改對象的持久化狀態(tài)。為了防止finalize被惡意攻擊漏益,可以把finalize方法設置為final蛹锰。
finalize的常用場景:
public class FileOutputStream extends OutputStream{
protected void finalize() throws IOException {
// Android-added: CloseGuard support.
if (guard != null) {
guard.warnIfOpen();
}
if (fd != null) {
if (fd == FileDescriptor.out || fd == FileDescriptor.err) {
flush();
} else {
// Android-removed: Obsoleted comment about shared FileDescriptor handling.
close();
}
}
}
{
應該以finalize為時間點,為對象的回收做準備绰疤,以上面的FileOutputStream為例铜犬,在finalize執(zhí)行時,清除緩沖區(qū)或關閉文件流轻庆,保證對象在回收時不會產(chǎn)生內(nèi)存問題癣猾。如果你希望你的對象具有自動回收功能,可以實現(xiàn)AutoCloseable接口余爆,并在finalize中調(diào)用實現(xiàn)close方法纷宇。
9、使用try with resource 替換 try-finally
請注意蛾方,此語法Java 7以下不支持像捶。
我們經(jīng)常使用FileInputStream或FileOutStream等資源型的類上陕,需要在使用結束后,及時關閉資源作岖。在過去唆垃,使用try-finally是最好的方式:
static String firstLineOfFile(String path) throws IOException {
BufferedReader br = new BufferedReader(newFileReader(path));
try {
return br.readLine();
} finally {
br.close();
}
}
如果一次操作使用多次資源型的類,例如以下代碼:
static void copy(String src, String dst) throws IOException {
InputStream in = new FileInputStream(src);
try {
OutputStream out = new FileOutputStream(dst);
try {
byte[] buf = new byte[BUFFER_SIZE];
int n;
while ((n = in.read(buf)) >= 0)
out.write(buf, 0, n);
} finally {
out.close();
}
} finally {
in.close();
}
}
以上代碼存在以下缺點:
- 因為要關閉資源痘儡,導致上面的代碼需要有多個try-finally辕万,可讀性上并不好
- close方法本身也會拋出異常
- 兩個資源型的操作互相影響
如果資源性的操作再復雜一些,代碼會更加復雜沉删,為了解決這個問題渐尿,在Java 7之后提供了新的語法:
static String firstLineOfFile(String path) throws IOException {
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
return br.readLine();
}
}
static void copy(String src, String dst) throws IOException {
try (InputStream in = new FileInputStream(src); OutputStream out = new FileOutputStream(dst)) {
byte[] buf = new byte[BUFFER_SIZE];
int n;
while ((n = in.read(buf)) >= 0)
out.write(buf, 0, n);
}
}
此語法要求try方法內(nèi)的資源必須實現(xiàn)AutoCloseable接口,如果發(fā)生了異常矾瑰,會自動調(diào)用該類的close方法砖茸。同樣支持try-catch捕獲指定的異常。
static String firstLineOfFile(String path, String defaultVal) {
try (BufferedReader br = new BufferedReader(new FileReader(path))) {
return br.readLine();
} catch (IOException e) {
return defaultVal;
}
}
10殴穴、遵循重寫Object的equals方法的規(guī)則
重寫Object的equals方法雖然很簡單凉夯,但是有很多種方式出錯,并且后果很嚴重采幌。一般來說我們不必重寫equals方法劲够,因為每一個Object的equals已經(jīng)保證了它的唯一性,如果必須要重寫他休傍,要注意以下原則:
- 自反性:x.equals(x)征绎,必須返回true;
- 對稱性:x.equals(y) == y.equals(x);
- 傳遞性:如果x.equals(y) ==true磨取,y.equals(z) == true, 所以x.equals(z) == true;
- 一致性:x.equals(y)的結果人柿,如果未發(fā)生改變,無論調(diào)用多少次都會得到同一個結果忙厌;
- 非空性:x非空凫岖,x.equals(null)必須返回false;
其他判斷相等的方法:
- 數(shù)字的比較逢净,如果不是float和double隘截,可以直接使用==判斷相等,如果是float汹胃,使用Float.compare(float, float),如果是Double东臀,使用Double.compare(double, double)着饥;
- 如果需要判斷數(shù)組的每一個元素相等,可以考慮使用Arrays.equals()方法惰赋;
- 避免判斷空指針宰掉,可以使用Objects.equals()方法呵哨;
如果需要重寫equals,也一定還要重寫hashcode轨奄,并且遵循equals的方法孟害。