java循坏_Java的坏功能是什么
java循壞
總覽
當(dāng)您第一次學(xué)習(xí)開發(fā)時,您會看到關(guān)于不同功能的過分籠統(tǒng)的陳述,它們對于設(shè)計,性能,清晰度,可維護(hù)性都是不好的,感覺就像是黑客,或者他們只是不喜歡它。
這可能會得到現(xiàn)實(shí)世界經(jīng)驗(yàn)的支持,在實(shí)際經(jīng)驗(yàn)中,刪除功能的使用可以改善代碼。 有時這是因?yàn)殚_發(fā)人員不知道如何正確使用該功能,或者該功能固有地容易出錯(取決于您是否喜歡它)
當(dāng)時尚或您的團(tuán)隊改變并且此功能變得很好甚至是首選方法時,這令人感到不安。
在這篇文章中,我將介紹一些人們討厭的功能,以及為什么我認(rèn)為使用正確的功能應(yīng)該是有益的力量。 功能并不像是/否,好/壞,就像許多人相信的那樣。
檢查異常
對于開發(fā)人員不喜歡考慮錯誤處理的程度,我經(jīng)常感到驚訝。 新開發(fā)人員甚至不喜歡閱讀錯誤消息。 這是艱苦的工作,他們抱怨應(yīng)用程序崩潰,“它不起作用”。 他們不知道為什么錯誤消息和堆棧轉(zhuǎn)儲經(jīng)常告訴他們?nèi)绻麄冎荒芸吹骄€索的地方到底出了什么問題,為什么會引發(fā)異常。 當(dāng)我出于跟蹤目的而寫出堆棧跟蹤信息時,許多人只會看到日志沒有錯誤時就像崩潰一樣。 閱讀錯誤消息是一種技巧,起初它可能會讓人不知所措。
同樣,也經(jīng)常避免以有用的方式處理異常。 我不知道該異常該怎么辦,我寧愿記錄該異常并假裝該異常未發(fā)生,或者只是炸掉,然后讓操作人員或GUI用戶處理錯誤的能力最弱。
結(jié)果,許多經(jīng)驗(yàn)豐富的開發(fā)人員都討厭檢查異常。 但是,我聽到的越多,我越高興Java檢查了異常,因?yàn)槲覉孕臞ava確實(shí)會發(fā)現(xiàn)忽略異常非常容易,并且只要不被它們煩惱就讓應(yīng)用程序死亡。
檢查異常當(dāng)然可以被過度使用。 問題應(yīng)該是在引發(fā)檢查異常時; 我是否想通過迫使他們對錯誤處理進(jìn)行一點(diǎn)思考來惹惱開發(fā)人員調(diào)用代碼? 如果答案是肯定的,則拋出一個已檢查的異常。
恕我直言,這是lambda設(shè)計的失敗,因?yàn)樗鼰o法透明地處理檢查的異常。 例如,作為自然代碼塊,可以拋出未處理的異常,就像處理未經(jīng)檢查的異常和錯誤一樣。 但是,考慮到lambda和函數(shù)式編程的歷史,它們根本不喜歡副作用,更不用說快捷錯誤處理了,這也就不足為奇了。
您可以通過重新拋出已檢查的異常(好像它是未檢查的異常)來解決lambda的限制。 之所以可以這樣做是因?yàn)镴VM沒有檢查異常的概念,它像泛型一樣是編譯時檢查。 我的首選方法是使用Unsafe.rethrowException,但還有3種其他方式可以做到這一點(diǎn)。 盡管Thread.currentThread()。stop(e)總是很安全,但它在Java 8中不再起作用。
Thread.currentThread()。stop(e)不安全嗎?
當(dāng)方法Thread.stop(Throwable)可能導(dǎo)致另一個線程在代碼的隨機(jī)部分觸發(fā)異常時,它是不安全的。 這可能是一部分代碼中未檢查到的異常,也可能是拋出該異常的原因,該異常捕獲在線程的某些部分,但其他部分則使您不知所措。
但是,它不安全的主要原因是,它可能會使原子操作處于不一致狀態(tài)的代碼鎖定部分的同步狀態(tài),從而以微妙且不可測試的方式破壞內(nèi)存。
更令人困惑的是,Throwable的堆棧跟蹤與實(shí)際引發(fā)異常的線程的堆棧跟蹤不匹配。
但是Thread.currentThread()。stop(e)呢? 這將觸發(fā)當(dāng)前線程在當(dāng)前行上引發(fā)異常。 這并不比僅使用throw異常執(zhí)行正在執(zhí)行的編譯器無法檢查的操作更糟。 問題是編譯器并不總是知道您在做什么,以及它是否真的安全。 對于仿制藥,這被歸類為“未經(jīng)檢查的演員表”,這是一個警告,您可以通過注釋將其禁用。 Java不能很好地支持帶有已檢查異常的同類操作,您最終會使用hack,或者更糟的是將真正的已檢查異常隱藏為運(yùn)行時異常,這意味著調(diào)用者無法正確處理它。
使用
對我來說,這是一個新的“規(guī)則”。 我知道它來自哪里,但是該規(guī)則比應(yīng)該應(yīng)用的地方有更多例外。 讓我們首先考慮所有可以使用重載static的上下文。
我同意使用靜態(tài)可變字段很可能是新手錯誤,還是有可能避免的事情。 如果您看到靜態(tài)字段在構(gòu)造函數(shù)中被更改,則幾乎可以肯定是一個錯誤(即使沒有,我也會避免),我相信這是避免所有靜態(tài)語句的原因。
但是,在所有其他情況下,使用static不僅性能更高,而且更清楚。 它顯示此字段對于每個實(shí)例都不同,或者該方法或類并不隱式依賴于實(shí)例。
簡而言之,static是好的,可變的static字段是例外,而不是規(guī)則。
Singletons不好嗎?
單例的問題來自兩個方向。 它們是有效的全局可變狀態(tài),使其難以維護(hù)或封裝(例如在單元測試中),并且支持自動接線。 也就是說,任何組件都可以訪問它,從而使您的依賴項(xiàng)變得不清楚并且難以管理。 由于這些原因,一些開發(fā)人員討厭它們。
但是,遵循良好的依賴關(guān)系注入是一種應(yīng)該應(yīng)用于所有組件(無論是否單例)的方法,并且應(yīng)該避免通過單例避免全局可變狀態(tài)。
如果排除全局狀態(tài)和自連接組件,則剩下的Singleton是不可變的,并通過依賴注入傳遞,在這種情況下,它們可以正常工作。 我用于實(shí)現(xiàn)策略的一種常見模式是將枚舉與一個實(shí)現(xiàn)接口的實(shí)例一起使用。
enum MyComparator implements Comparator {INSTANCE;public int compare(MyObject o1, MyObject o2) {// something a bit too complicated to put in a lambda}}該實(shí)例可以通過依賴項(xiàng)注入作為Comparator的實(shí)現(xiàn)傳遞,并且沒有可變狀態(tài),可以在線程和單元測試之間安全地使用它。
我可以讓一個庫或框架為我做一件非常簡單的事情嗎?
庫和框架可以為您節(jié)省大量時間和精力,使您自己的代碼執(zhí)行在其他地方已經(jīng)可以使用的操作。
即使您想編寫自己的代碼,我也強(qiáng)烈建議您了解現(xiàn)有庫和框架的功能,以便從中學(xué)習(xí)。 自己編寫它不是避免理解任何現(xiàn)有解決方案的捷徑。 一位記者曾經(jīng)絕望地寫到一位有抱負(fù)的記者。 不喜歡讀書,只喜歡寫作。 在軟件開發(fā)中也是如此。
但是,我已經(jīng)看到(在Stackoverflow上)開發(fā)人員竭盡全力避免將自己的代碼用于瑣碎的示例。 他們覺得如果使用庫,它必須比他們編寫的任何東西都要好。 問題在于它是假定的。 添加庫不會增加復(fù)雜性,您對庫有很好的了解,而且您將不需要學(xué)習(xí)編寫可以信任的代碼。
一些開發(fā)人員使用框架來幫助學(xué)習(xí)實(shí)際上是一種方法論。 實(shí)際上,開發(fā)人員通常會使用純Java進(jìn)行依賴注入的框架,但是他們要么不信任自己,要么不信任自己的團(tuán)隊來這樣做。
在高性能空間中,代碼越簡單,應(yīng)用程序所做的工作就越少,使用更少的活動部件進(jìn)行維護(hù)就越容易,并且運(yùn)行速度也就越快。 您需要使用最少的庫和框架,這些庫和框架應(yīng)相當(dāng)容易理解,以便使系統(tǒng)發(fā)揮最佳性能。
用雙倍賺錢不好嗎?
使用小數(shù)而不考慮舍入會給您帶來意想不到的結(jié)果。 從正面看,對于雙精度數(shù),通常顯然是錯誤的,例如10.99999999999998,而不是11。
有些人認(rèn)為BigDecimal是解決方案。 但是,問題在于BigDecimal具有自己的陷阱,很難進(jìn)行驗(yàn)證/讀取/寫入,但是如果沒有,最糟糕的情況是看起來正確。 舉個例子:
double d = 1.0 / 3 * 3 + 0.01;BigDecimal bd1 = BigDecimal.valueOf(1.0).divide(BigDecimal.valueOf(3), 2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(3)).add(BigDecimal.valueOf(0.01)).setScale(2, BigDecimal.ROUND_HALF_UP);BigDecimal bd2 = BigDecimal.valueOf(1.0).divide(BigDecimal.valueOf(3), 2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(3).add(BigDecimal.valueOf(0.01))).setScale(2, BigDecimal.ROUND_HALF_UP);System.out.println("d: " + d);System.out.println("bd1: " + bd1);System.out.println("bd2: " + bd2);這將產(chǎn)生三個不同的結(jié)果。 通過觀察,哪一個產(chǎn)生正確的結(jié)果? 您能說出bd1和bd2之間的區(qū)別嗎?
打印:
d: 1.01 bd1: 1.00 bd2: 0.99您可以從輸出中看到哪個錯誤嗎? 實(shí)際上答案應(yīng)該是1.01。
BigDecimal的另一個難題是equals和compareTo的行為不同。 當(dāng)compareTo()返回0時,equals()可以為false。即,在BigDecimal 1.0中,等于1.00時為false,因?yàn)楸壤煌?
BigDecimal的問題在于,您獲得的代碼通常更難于理解,并且會產(chǎn)生看起來不正確的錯誤結(jié)果。 BigDecimal的速度明顯較慢,并且會產(chǎn)生大量垃圾。 (這在Java 8的每個版本中都在改進(jìn))在某些情況下,BigDecimal是最佳解決方案,但并非如某些人所反對的那樣。
如果BigDecimal不是一個很好的選擇,還有其他嗎? int和long通常以固定的精度使用,例如,整數(shù)而不是分?jǐn)?shù)。 這有一些挑戰(zhàn),您必須記住小數(shù)位在哪里。 如果Java支持值類型,將它們用作金錢包裝器并為您提供更多安全性可能是有意義的,但是處理整數(shù)基元的控制,說明和性能可能會有所提高。
使用
對于NullPointerException Java的開發(fā)人員而言,重復(fù)獲得NullPointerException是一種消耗體力的經(jīng)歷。 我真的必須為Java中數(shù)組中的每個對象,每個元素創(chuàng)建一個新實(shí)例嗎? 其他語言則不需要這樣做,因?yàn)橥ǔJ峭ㄟ^嵌入式數(shù)據(jù)結(jié)構(gòu)來完成的。 (某些正在考慮用于Java的東西)
即使是經(jīng)驗(yàn)豐富的Java開發(fā)人員也難以處理null值,并且將這種語言的null視為一個大錯誤。 恕我直言,問題在于替代品通常更差。 例如不是NPE的NULL對象,但也許應(yīng)該已經(jīng)初始化為其他對象。 在Java 8中,Optional是一個很好的添加,它使對非結(jié)果的處理更加清晰。 我認(rèn)為這對于那些與NullPointerException斗爭的人很有用,因?yàn)樗仁鼓紤]可能根本沒有結(jié)果。 這不能解決未初始化字段的問題。
我個人不喜歡它,因?yàn)樗鉀Q了一個問題,可以通過正確處理null來更廣泛地解決問題,但是我知道對于許多人來說,這是一種改進(jìn)。
一個常見的問題是; 我應(yīng)該如何知道變量為空? 這是我心中錯誤的方法。 應(yīng)該是,為什么要假設(shè)它不能為null? 如果您不能回答該問題,則必須假定它可以為null,并且如果不進(jìn)行檢查,NPE也就不會感到驚訝。
您可能會爭辯說Java可以使用更多的語法糖來制作處理Elvis運(yùn)算符之類的null清除程序的代碼,但我認(rèn)為問題在于開發(fā)人員沒有充分考慮null值。 例如,您是否在打開枚舉變量之前檢查它是否為null? (我認(rèn)為應(yīng)該有一個case null的case null :在switch中,但不存在或陷入default :但事實(shí)并非如此)
快速編寫代碼有多重要?
Java不是一種簡潔的語言,沒有IDE可以為您編寫一半的代碼,如果您花了一整天時間編寫代碼,那么編寫esp將會非常痛苦。
但這就是開發(fā)人員整日不做的事情嗎? 實(shí)際上,他們沒有。 開發(fā)人員不會花費(fèi)很多時間來編寫代碼,他們會花費(fèi)90%(用于新代碼)到99%(用于遺留代碼)來理解問題 。
你可能會說; 我一整天以后寫一千行代碼,然后重新編寫代碼(通常使其更短),一段時間后我修復(fù)了代碼。但是,盡管您仍然想起這段代碼,但是如果您只是編寫最后需要的代碼(或從打印輸出中完成),然后將其除以在項(xiàng)目上花費(fèi)的總時間,從頭到尾,您可能會發(fā)現(xiàn)實(shí)際上每天少于100行代碼,每天可能少于10行。
所以,如果那段時間不是寫最終產(chǎn)品,那您實(shí)際上在做什么? 據(jù)了解,最終用戶需要什么,以及實(shí)施該解決方案需要什么。
曾經(jīng)有人告訴我; 如果您在錯誤的位置鉆Kong,則無論鉆Kong多快,多大,有多深或有多少個Kong都無所謂。
結(jié)論
我聽到了從初學(xué)者到杰出開發(fā)人員的觀點(diǎn),聲稱您不應(yīng)該/我無法想象為什么/如果您使用X,您應(yīng)該被解雇,應(yīng)該只使用Y。我發(fā)現(xiàn)這樣的陳述很少是100%準(zhǔn)確的。 通常,要么存在極端情況,有時在非常常見的情況下,這種陳述具有誤導(dǎo)性或完全不正確。
我會持懷疑態(tài)度來對待任何這樣的廣泛評論,而且他們常常發(fā)現(xiàn)一旦發(fā)現(xiàn)其他人沒有相同的看法,他們就必須限定所說的內(nèi)容。
翻譯自: https://www.javacodegeeks.com/2015/05/what-are-the-bad-features-of-java.html
java循壞
總結(jié)
以上是生活随笔為你收集整理的java循坏_Java的坏功能是什么的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: javafx 项目_JavaFX,Jig
- 下一篇: 摆脱冷气_摆脱匿名类