finally是Java中一個非常常見的關鍵詞,我們經常使用這個關鍵詞來做一些後置操作,我們先來看一下finally的基本用法
finally的基本用法
// 方式一:try catch finally 捕獲異常
try {
} catch(Exception e) {
} finally {
}
// 方式二 不捕獲異常,
try {
} finally {
}
我們看到了finally的用法,那麼finally被經常用作幹什麼呢?
finally的作用
- 釋放流
public static void testReleaseStream() {
File file = new File("D:\\logs\\common-error.log");
FileInputStream fis = null;
try {
StringBuilder sb = new StringBuilder();
fis = new FileInputStream(file);
int len;
byte[] buf = new byte[1024];
while ((len = fis.read(buf)) != -1) {
sb.append(new String(buf, 0, len));
}
System.out.println(sb.toString());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
- 釋放記憶體
private static Map<String, Student> studentCache = new HashMap<>();
public static void refreshCache() {
Map<String, Student> oldCache = studentCache;
try {
Map<String, Student> student = getStudent();
studentCache = student;
} finally {
oldCache.clear();
}
}
// 模拟擷取緩存
private static Map<String, Student> getStudent() {
return new HashMap<>();
}
- 移除ThreadLocal變量
private static final ThreadLocal<String> stringThreadLocal = new ThreadLocal<>();
public static void testReleaseThreadLocal() {
try {
stringThreadLocal.set("test");
// 執行相關業務代碼
} finally {
stringThreadLocal.remove();
}
}
回到我們今天要看的核心問題,finally塊一定會執行麼?實際上,finally不一定會執行
- 未進入try代碼塊
當代碼并未執行帶try的代碼塊時,finally并不會被執行
- 執行了System.exit(0);
當執行System.exit(0);時,JVM會直接退出,是以finally代碼塊不會執行
這兩個情況我們需要關注第一種情況,因為第二種一般都不會使用。
public static void testReleaseThreadLocal() {
stringThreadLocal.set("test");
// 在此處執行某些代碼,并且出現異常
try {
// 執行相關業務代碼
} finally {
stringThreadLocal.remove();
}
System.exit(0);
}
假如我們使用上面的方式來使用try finally,那麼finally代碼塊便不會執行,ThreadLocal也不會被清理,而我們采用下面的方式便不會出現問題
public static void testReleaseThreadLocal() {
try {
stringThreadLocal.set("test");
// 在此處執行某些代碼,并且出現異常
// 執行相關業務代碼
} finally {
stringThreadLocal.remove();
}
System.exit(0);
}
當使用上面的方式時,即使代碼出現異常,finally代碼塊也會執行,是以ThreadLocal可以正常清理
進階
我們來簡單介紹一下關閉流的進階用法
public static void tryAdvance() {
File file = new File("D:\\logs\\common-error.log");
try (FileInputStream fis = new FileInputStream(file)) {
StringBuilder sb = new StringBuilder();
int len;
byte[] buf = new byte[1024];
while ((len = fis.read(buf)) != -1) {
sb.append(new String(buf, 0, len));
}
System.out.println(sb.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
以前我們都需要手動關閉流,每次都需要寫一堆關閉流的代碼,一點都不好看,通過這種方式,便可以實作自動關閉流,這個就是常說的try-with-resources語句