-
final關(guān)鍵字:
- 可以將方法或者類聲明為final,明確告訴不可以被修改啦鸣。如Java類庫的一些基礎(chǔ)類中相當(dāng)一部分被聲明為final class潮饱,這樣做可以有效避免API使用者更改基礎(chǔ)功能,同樣也是保證平臺安全的必要手段赏陵。
- 使用final修飾參數(shù)或者變量饼齿,也可以清楚地避免意外賦值導(dǎo)致的邊城錯誤,甚至蝙搔,有人明確推薦將所有方法參數(shù)缕溉、本地變量、成員變量聲明成final吃型。
- Final變量產(chǎn)生了某種程度的不可變(immutable)的效果证鸥,所以可以用于保護(hù)只讀數(shù)據(jù),尤其是在并發(fā)編程中勤晚,因為明確地不能再賦值final變量枉层,有利于減少額外的同步開銷,也可以省去一些防御性拷貝的必要赐写。
- Final 也許會有性能的好處鸟蜡, 可以利用final幫助JVM將方法進(jìn)行內(nèi)聯(lián),可以改善編譯器進(jìn)行條件編譯的能力等等挺邀。但這些僅僅是基于假設(shè)得出的結(jié)論揉忘,比如JVM(Hotspot)判斷內(nèi)聯(lián)未必依賴final的提示,以及還有很多類似的端铛,final字段對性能的影響泣矛,大部分情況可以忽略。
- 在實際開發(fā)場景中禾蚕,除非特別考慮性能環(huán)節(jié)您朽,不然最好不要指望這種小技巧帶來的所謂性能好處,程序本身就應(yīng)該體現(xiàn)它的語義目的换淆。
-
finally關(guān)鍵字:
- 明確知道如何使用finally
- 需要關(guān)閉的鏈接等資源哗总,可以使用Java7中添加的try-with-resources語句几颜,通常情況下Java平臺本身可以更好的處理異常情況,編碼量也要少很多
-
finalize關(guān)鍵字:
- 明確知道已經(jīng)不推薦使用魂奥,并且Java9將Object.finalize()標(biāo)記為deprecated,
- 不要指望利用finalize來資源回收菠剩,因為我們無法保證finalize什么時候執(zhí)行,執(zhí)行的是否符合預(yù)期耻煤,使用不當(dāng)還會影響性能具壮,導(dǎo)致程序死鎖、掛起等哈蝇。
-
finalize的問題棺妓?真的那么不好用?
- 為啥導(dǎo)致不好用?finalize的執(zhí)行是和垃圾收集關(guān)聯(lián)在一起的炮赦,一旦實現(xiàn)了非空的finalize方法怜跑,就會導(dǎo)致相應(yīng)對象回收呈現(xiàn)數(shù)量級上的變慢,benchmark顯示大概會有40~50倍的下降吠勘。
- finalize被設(shè)計成災(zāi)對象被垃圾回收前調(diào)用性芬,就是意味著實現(xiàn)了finalize的方法的對象是“特殊公民”,JVM要懟它進(jìn)行額外處理剧防。finalize本質(zhì)上成為了快速回收的阻礙者植锉,可能導(dǎo)致你的對象經(jīng)過多個垃圾收集周期才能被收回
- System.runFinalization()告訴JVM積極一點,是不是就可以滿足快速垃圾回收峭拘,但這種方式本身是不可預(yù)測情況發(fā)生的俊庇,并且不能保證,所以在本質(zhì)上不能指望這么操作以解決問題鸡挠,現(xiàn)實環(huán)境中辉饱,由于finalize拖慢垃圾收集,導(dǎo)致大量對象堆積拣展,也是一種典型的導(dǎo)致OOM的原因
- 不要指望利用finalize來資源回收彭沼,因為我們無法保證finalize什么時候執(zhí)行,執(zhí)行的是否符合預(yù)期备埃,使用不當(dāng)還會影響性能溜腐,導(dǎo)致程序死鎖、掛起等瓜喇。
- final可以用來修飾類、方法歉糜、變量乘寒,分別有不同的意義,final修飾的class代表不可以繼承擴(kuò)展匪补,final的變量是不可以修改的伞辛,而final的方法也是不可以重寫的(override)
- finally則是Java保證重點代碼一定要被執(zhí)行的一種機(jī)制烂翰。我們可以使用try-finally或者try-catch-finally來進(jìn)行類似關(guān)閉JDBC連接、保證unlock鎖等操作
- finalize是基礎(chǔ)類Java.lang.Object的一個方法蚤氏,它的設(shè)計目的是保證對象在被垃圾收集前完成特定資源的回收甘耿。finalize機(jī)制現(xiàn)在已經(jīng)不推薦使用,并且在JDK9開始被標(biāo)記deprecated
- 問題:從概念上理解語法規(guī)范上的理解就是以上說法竿滨,但從全面的只是體系出發(fā)分析圍繞性能佳恬、并發(fā)、對象生命周期或垃圾收集基本過程等方面的理解
-
擴(kuò)展情況
- 注意1.final不是immutable(不可變)
final List<String> strList = new ArrayList<>();
strList.add(“hello”);
strList.add(“world”);
List<String> unmodifiableStrList = List.of(“hello”, “world”);
unmodifiableStrList.add(“agin”);
- final只能約束strList這個引用不可以被賦值于游,但是strList對象行為不被final影響毁葱,添加元素等操作完全正常的。如果我們真的希望對象本身是不可變的贰剥,那么需要相應(yīng)的類支持不可變的行為倾剿。在上面這個例子中,List.of方法創(chuàng)建的本身就是不可變的List蚌成,最后那句add是會在運(yùn)行時拋出異常的前痘。
- Immutable在很多場景是很好的選擇,Java目前沒有原生的不可變支持担忧,如果要實現(xiàn)immutable的類芹缔,我們需要滿足一下條件:
- 將class自身聲明為final,這樣別人就不能擴(kuò)展來繞過限制了
- 將所有成員變量定義為private和final涵妥,且不要實現(xiàn)setter方法
- 通常構(gòu)造對象時乖菱,成員變量使用深度拷貝來初始化,而不是直接賦值蓬网,這是一種防御措施窒所,因為這個環(huán)節(jié)無法確定輸入對象不被其他人修改。
- 如果確實需要實現(xiàn)getter方法帆锋,或者其他可能會返回內(nèi)部狀態(tài)的方法吵取,使用copy-on-write原則,創(chuàng)建私有的copy
- 關(guān)于setter锯厢、getter方法皮官,建議最好是確定需要再生成
-
finalize的替代方案:
- Cleaner的實現(xiàn)利用了幻象引用(PhantomReference)這是一種常見的post-mortem 清理機(jī)制,利用幻象引用和引用隊列实辑,我們可以保證對象被徹底銷毀前做一些類似資源回收的工作捺氢,比如關(guān)閉文件描述符,這種方式比finalize更輕量剪撬、更加可靠一點
- 每個Cleaner的操作都是獨立的摄乒,有自己的運(yùn)行線程,這樣也就避免意外死鎖等問題
- 雖然如此,但Cleaner或者幻象引用改善的成仍然有限的馍佑,如果由于種種原因?qū)е禄孟笠枚逊e斋否,同樣會出現(xiàn)問題。所以Cleaner適合作為一種最后的保證手段拭荤,不能完全依賴
- 常見的使用幻象引用機(jī)制有MYSQL JDBC driver之一的mysql-connector-j,幻象引用也可以進(jìn)行類似鏈條式依賴關(guān)系的動作茵臭,比如,進(jìn)行總量控制的場景舅世,保證只有連接被關(guān)閉旦委,相應(yīng)資源被回收,連接池才能創(chuàng)建新的連接
總結(jié)Summary
- 一般情況歇终,利用try-with-resourcs 或者try-finally機(jī)制社证,是非常好的回收資源的辦法。如果特殊情況需要額外處理评凝,可以考慮Java提供的Cleaner機(jī)制或者其他替代方法
- 回收資源是因為資源都是有限的追葡,垃圾收集時間的不可預(yù)測,可能會機(jī)打家具資源占用奕短。這意味著對于消耗非常高頻的資源宜肉,不能通過finalize去承擔(dān)資源釋放的主要職責(zé),最多讓finalize作為最后的守門員翎碑,況且它已經(jīng)被實踐中暴露出問題谬返,所以建議資源用完即顯式釋放,或者利用資源池來盡量重用日杈。
-
不要在finally中使用return語句