日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

编码Java时的10个微妙的最佳实践

發(fā)布時間:2023/12/3 java 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 编码Java时的10个微妙的最佳实践 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

這是10個最佳實踐的列表,這些最佳實踐比您的平均Josh Bloch有效Java規(guī)則要微妙得多。 盡管Josh Bloch的列表很容易學(xué)習,并且涉及日常情況,但此處的列表包含了涉及API / SPI設(shè)計的較不常見的情況,但可能會產(chǎn)生很大的影響。

我在編寫和維護jOOQ時遇到了這些問題, jOOQ是Java中的內(nèi)部DSL建模SQL。 作為內(nèi)部DSL,jOOQ最大限度地挑戰(zhàn)了Java編譯器和泛型, 將泛型,可變參數(shù)和重載組合在一起,這是Josh Bloch可能不推薦使用的“平均API”。

讓我與您分享編碼Java時的10個微妙的最佳實踐:

1.記住C ++析構(gòu)函數(shù)

還記得C ++析構(gòu)函數(shù)嗎? 沒有? 然后,您可能會很幸運,因為您無需再調(diào)試任何代碼,因為刪除對象后沒有釋放分配的內(nèi)存,因此不會留下內(nèi)存泄漏。 感謝Sun / Oracle實現(xiàn)垃圾回收!

但是,盡管如此,破壞者還是有一個有趣的特征。 通常以相反的順序釋放內(nèi)存是有意義的。 在使用類似析構(gòu)函數(shù)的語義進行操作時,也要在Java中記住這一點:

  • 當使用@Before和@After JUnit批注時
  • 分配時,釋放JDBC資源
  • 調(diào)用超級方法時

還有其他各種用例。 這是一個具體示例,顯示了如何實現(xiàn)某些事件偵聽器SPI:

@Override public void beforeEvent(EventContext e) {super.beforeEvent(e);// Super code before my code }@Override public void afterEvent(EventContext e) {// Super code after my codesuper.afterEvent(e); }

另一個臭名昭著的餐飲哲學(xué)家問題就是一個很好的例子,說明了為什么這很重要。

餐飲哲學(xué)家。 在這里看到: http : //adit.io/posts/2013-05-11-The-Dining-Philosophers-Problem-With-Ron-Swanson.html

規(guī)則 :無論何時使用before / after,allocate / free,take / return語義實現(xiàn)邏輯,請考慮after / free / return操作是否應(yīng)按相反的順序執(zhí)行操作。

2.不要相信您早期的SPI發(fā)展判斷

向消費者提供SPI是允許他們將自定義行為注入您的庫/代碼中的簡便方法。 不過請注意,您的SPI演變判斷可能會欺騙您,使您認為(不需要)該附加參數(shù) 。 確實, 不應(yīng)及早添加任何功能。 但是一旦發(fā)布了SPI,并決定遵循語義版本控制 ,當您意識到在某些情況下可能還需要另一個參數(shù)時,您會后悔自己在SPI中添加了一個愚蠢的單參數(shù)方法:

interface EventListener {// Badvoid message(String message); }

如果還需要消息ID和消息源怎么辦? API的發(fā)展將阻止您輕松地將該參數(shù)添加到上述類型。 使用Java 8,您可以添加防御者方法來“捍衛(wèi)”您糟糕的早期設(shè)計決策:

interface EventListener {// Baddefault void message(String message) {message(message, null, null);}// Better?void message(String message,Integer id,MessageSource source); }

請注意,不幸的是,防御者方法不能設(shè)為final 。

但是,比使用數(shù)十種方法污染SPI更好的方法是,僅為此目的使用上下文對象(或參數(shù)對象) 。

interface MessageContext {String message();Integer id();MessageSource source(); }interface EventListener {// Awesome!void message(MessageContext context); }

與EventListener SPI相比,您可以更輕松地開發(fā)MessageContext API,因為實施該應(yīng)用程序的用戶將更少。

規(guī)則 :無論何時指定SPI,都應(yīng)考慮使用上下文/參數(shù)對象,而不要編寫帶有固定數(shù)量參數(shù)的方法。

備注 :通常也可以通過專用的MessageResult類型(可以通過構(gòu)建器API構(gòu)造)來傳遞結(jié)果,這是一個好主意。 這將為您的SPI增加更多的SPI演進靈活性。

3.避免返回匿名,本地或內(nèi)部類

Swing程序員可能有幾個鍵盤快捷鍵可以為其數(shù)百個匿名類生成代碼。 在許多情況下,創(chuàng)建它們很不錯,因為您可以本地遵守接口,而無需經(jīng)歷思考完整SPI子類型生命周期的“麻煩”。

但是,您不應(yīng)該過于頻繁地使用匿名類,局部類或內(nèi)部類,原因很簡單:它們保留對外部實例的引用。 并且,如果您不小心,它們會將外部實例拖到任何地方,例如,拖到本地類之外的某個范圍。 這可能是內(nèi)存泄漏的主要來源,因為整個對象圖會突然以微妙的方式糾纏在一起。

規(guī)則 :每當編寫匿名,本地或內(nèi)部類時,請檢查是否可以使其成為靜態(tài)類,甚至是常規(guī)頂級類。 避免將匿名,本地或內(nèi)部類實例從方法返回到外部作用域。

備注 :對于簡單對象實例化,圍繞雙花括號有一些聰明的做法:

new HashMap<String, String>() {{put("1", "a");put("2", "b"); }}

這利用了JLS§8.6中指定的 Java實例初始化程序 。 看起來不錯(也許有點奇怪),但確實是個壞主意。 原來是完全獨立的HashMap實例現(xiàn)在將保留對外部實例的引用,無論發(fā)生什么情況。 此外,您將創(chuàng)建一個其他類供類加載器管理。

4.立即開始編寫SAM!

Java 8正在敲門。 隨Java 8一起提供lambda ,無論您是否喜歡。 不過,您的API使用者可能會喜歡它們,因此您最好確保他們可以盡可能多地使用它們。 因此,除非您的API接受簡單的“標量”類型(例如int , long , String , Date ,否則您的API應(yīng)盡可能多地接受SAM。

什么是SAM? SAM是單一抽象方法[Type]。 也稱為功能接口 ,很快將使用@FunctionalInterface注釋進行注釋 。 這與規(guī)則2配合得很好,其中EventListener實際上是SAM。 最好的SAM是具有單個參數(shù)的SAM,因為它們將進一步簡化lambda的編寫。 想象寫作

listeners.add(c -> System.out.println(c.message()));

代替

listeners.add(new EventListener() {@Overridepublic void message(MessageContext c) {System.out.println(c.message()));} });

想象一下通過jOOX進行的 XML處理,它具有幾個SAM:

$(document)// Find elements with an ID.find(c -> $(c).id() != null)// Find their child elements.children(c -> $(c).tag().equals("order"))// Print all matches.each(c -> System.out.println($(c)))

規(guī)則 :與您的API使用者友好, 現(xiàn)在已經(jīng)編寫SAM /功能接口。

備注 :有關(guān)Java 8 Lambda和改進的Collections API的一些有趣的博客文章可以在這里找到:

  • http://blog.informatech.cr/2013/04/10/java-optional-objects/
  • http://blog.informatech.cr/2013/03/25/java-streams-api-preview/
  • http://blog.informatech.cr/2013/03/24/java-streams-preview-vs-net-linq/
  • http://blog.informatech.cr/2013/03/11/java-infinite-streams/

5.避免從API方法返回null

我曾經(jīng)寫過一兩次關(guān)于Java的NULL的博客。 我也寫了關(guān)于Java 8對Optional的介紹的博客。 從學(xué)術(shù)和實踐的角度來看,這些都是有趣的話題。

盡管NULL和NullPointerExceptions在Java中可能會持續(xù)一段時間,但是您仍然可以通過設(shè)計API來避免用戶遇到任何問題。 盡可能避免從API方法返回null。 您的API使用者應(yīng)能夠在適用的情況下鏈接方法:

initialise(someArgument).calculate(data).dispatch();

在上面的代碼段中,所有方法都不應(yīng)該返回null。 實際上,通常使用null的語義(缺少值)應(yīng)該是非常例外的。 在諸如jQuery (或jOOX ,其Java端口)之類的庫中,由于始終對可迭代對象進行操作 ,因此完全避免了null。 是否匹配某項與下一個方法調(diào)用無關(guān)。

由于延遲初始化,通常還會出現(xiàn)空值。 在許多情況下,也可以避免延遲初始化,而不會對性能產(chǎn)生重大影響。 實際上,僅應(yīng)謹慎使用惰性初始化。 如果涉及大型數(shù)據(jù)結(jié)構(gòu)。

規(guī)則 :盡可能避免從方法返回null。 僅將空值用于“未初始化”或“不存在”的語義。

6.切勿從API方法返回空數(shù)組或列表

雖然在某些情況下從方法返回null可以,但是絕對沒有用過返回null數(shù)組或null集合的用例! 讓我們考慮一下丑陋的java.io.File.list()方法。 它返回:

在此抽象路徑名表示的目錄中命名文件和目錄的字符串數(shù)組。 如果目錄為空,則數(shù)組為空。 如果此抽象路徑名不表示目錄,或者發(fā)生I / O錯誤,則返回null。

因此,處理此方法的正確方法是

File directory = // ...if (directory.isDirectory()) {String[] list = directory.list();if (list != null) {for (String file : list) {// ...}} }

空檢查真的必要嗎? 大多數(shù)I / O操作都會產(chǎn)生IOException,但是此操作返回null。 Null無法保存任何指示為什么發(fā)生I / O錯誤的錯誤消息。 因此,這在三種方式上是錯誤的:

  • 空無助于發(fā)現(xiàn)錯誤
  • Null不允許將I / O錯誤與不是目錄的File實例區(qū)分開
  • 每個人都會忘記空值

在集合上下文中,“空缺”的概念最好通過空數(shù)組或集合來實現(xiàn)。 除了再一次進行延遲初始化外,幾乎沒有有用的數(shù)組或集合。

規(guī)則 :數(shù)組或集合絕不能為空。

7.避免狀態(tài),發(fā)揮作用

HTTP的優(yōu)點在于它是無狀態(tài)的。 所有相關(guān)狀態(tài)都在每個請求和每個響應(yīng)中傳遞。 這對于REST的命名至關(guān)重要: 代表性狀態(tài)轉(zhuǎn)移 。 當用Java完成時,這也很棒。 當方法接收有狀態(tài)參數(shù)對象時,可以根據(jù)規(guī)則2來考慮它。 如果狀態(tài)在此類對象中傳遞,而不是從外部進行操縱,則事情會變得更加簡單。 以JDBC為例。 以下示例從存儲過程中獲取游標:

CallableStatement s =connection.prepareCall("{ ? = ... }");// Verbose manipulation of statement state: s.registerOutParameter(1, cursor); s.setString(2, "abc"); s.execute(); ResultSet rs = s.getObject(1);// Verbose manipulation of result set state: rs.next(); rs.next();

這些使JDBC成為難以處理的API。 每個對象都是難以置信的有狀態(tài)且難以操縱。 具體來說,有兩個主要問題:

  • 在多線程環(huán)境中正確處理有狀態(tài)的API非常困難
  • 很難使有狀態(tài)資源在全球范圍內(nèi)可用,因為沒有記錄狀態(tài)

阿甘正傳的戲劇海報, 派拉蒙影業(yè) ( Paramount Pictures)版權(quán)所有?1994。 版權(quán)所有。 可以相信上述用法滿足了所謂的合理使用

規(guī)則 :實施更多的功能樣式。 通過方法參數(shù)傳遞狀態(tài)。 操作較少的對象狀態(tài)。

8.短路equals()

這是一個低落的果實。 在大型對象圖中,如果所有對象的equals()方法首先比較便宜地比較身份,則可以顯著提高性能:

@Override public boolean equals(Object other) {if (this == other) return true;// Rest of equality logic... }

請注意,其他短路檢查可能涉及空檢查,該檢查也應(yīng)該存在:

@Override public boolean equals(Object other) {if (this == other) return true;if (other == null) return false;// Rest of equality logic... }

規(guī)則 :短路所有equals()方法以獲得性能。

9.嘗試使方法默認為final

有些人對此持不同意見,因為默認情況下使事情最終完成與Java開發(fā)人員所習慣的相反。 但是,如果您完全控制所有源代碼,則默認情況下將方法設(shè)為final絕對沒有問題,因為:

  • 如果確實需要重寫方法(確實嗎?),仍然可以刪除final關(guān)鍵字
  • 您再也不會意外覆蓋任何方法

這特別適用于靜態(tài)方法,在這些方法中“覆蓋”(實際上是陰影)幾乎沒有任何意義。 最近,我在Apache Tika上遇到了一個非常糟糕的陰影靜態(tài)方法示例。 考慮:

  • TaggedInputStream.get(InputStream)
  • TikaInputStream.get(InputStream)

TikaInputStream擴展了TaggedInputStream并使用完全不同的實現(xiàn)來隱藏其靜態(tài)get()方法。

與常規(guī)方法不同,靜態(tài)方法不會互相覆蓋,因為調(diào)用站點在編譯時綁定了靜態(tài)方法調(diào)用。 如果您不走運,您可能會偶然得到錯誤的方法。

規(guī)則 :如果您完全控制自己的API,請嘗試在默認情況下盡可能多地使用final方法。

10.避免方法(T…)簽名

偶爾接受一個Object...參數(shù)的“ accept-all” varargs方法沒有任何問題:

void acceptAll(Object... all);

編寫這樣的方法給Java生態(tài)系統(tǒng)帶來一點JavaScript的感覺。 當然,您可能希望將實際類型限制為在實際情況下更受限的內(nèi)容,例如String... 而且由于您不想限制太多,您可能會認為用通用T代替Object是一個好主意:

void acceptAll(T... all);

但事實并非如此。 T總是可以推斷為Object。 實際上,您最好不要將泛型與上述方法一起使用。 更重要的是,您可能認為可以重載上述方法,但是您不能:

void acceptAll(T... all); void acceptAll(String message, T... all);

看起來您可以選擇將String消息傳遞給該方法。 但是這里的電話怎么辦?

acceptAll("Message", 123, "abc");

編譯器會推斷<? extends Serializable & Comparable<?>> 為T <? extends Serializable & Comparable<?>> ,這使調(diào)用變得模棱兩可!

因此,每當您擁有“所有人都接受”的簽名(即使它是通用的)時,您將永遠無法再次安全地重載它。 API使用者可能只是幸運地“偶然地”選擇了編譯器選擇“正確的”最具體的方法。 但是他們也可能被欺騙使用“ accept-all”方法,或者根本無法調(diào)用任何方法。

規(guī)則 :如果可以,請避免“全部接受”簽名。 如果不能,則不要重載這種方法。

結(jié)論

Java是野獸。 與其他更高級的語言不同,它已經(jīng)發(fā)展到今天。 那可能是一件好事,因為在Java的發(fā)展速度下,已經(jīng)有數(shù)百個警告,這些警告只能通過多年的經(jīng)驗來掌握。

參考:在JAVA,SQL和JOOQ博客上,來自JCG合作伙伴 Lukas Eder的Java編碼Java時的10個最佳最佳實踐 。

翻譯自: https://www.javacodegeeks.com/2013/08/10-subtle-best-practices-when-coding-java.html

總結(jié)

以上是生活随笔為你收集整理的编码Java时的10个微妙的最佳实践的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 天天干狠狠插 | 日韩午夜在线 | 国产乱淫av一区二区三区 | 激情五月在线观看 | 花房姑娘免费观看全集 | 成人福利免费视频 | 男女搞鸡网站 | 91大神精品| 成人性爱视频在线观看 | 强行挺进白丝老师翘臀网站 | 99人妻碰碰碰久久久久禁片 | 欧美激情中文字幕 | 日韩少妇一区二区 | 韩国在线不卡 | 在线男人天堂 | 少妇搡bbbb搡bbb搡打电话 | 日本韩国在线观看 | 欧美一级在线观看视频 | 国产精品色婷婷 | 日批在线视频 | 国产视频综合 | 国产福利在线观看 | 理论片91| 性色av浪潮av| 欧美亚洲在线观看 | 日本一区二区在线免费 | 色网在线免费观看 | 欧美老熟妇喷水 | 性生交大片免费看狂欲 | 免费网站污 | av中文在线资源 | 精品视频一区二区在线观看 | 欧美xxxx日本和非洲 | 爱蜜臀av| 国产美女一区二区三区 | 日本高清不卡一区 | 欧美精品aa| 99久久久久久久 | 免费国产在线视频 | 北岛玲一区二区 | 91久久综合亚洲鲁鲁五月天 | 99爱这里只有精品 | www.黄色在线观看 | 91免费视频黄 | 国产男男网站 | 狠狠操在线 | 女人黄色片| 欧美成人一区二区在线 | hd性videos意大利精品 | 女十八毛片| 成人一级片视频 | 天天av天天操 | 美女毛毛片 | 久久久久噜噜噜亚洲熟女综合 | 涩里番在线观看 | 黑丝美女一区二区 | 中文字幕一区二区在线观看视频 | 肉色超薄丝袜脚交一区二区 | 日韩欧美在线视频免费观看 | 亚洲精品久久久蜜桃 | 91大神精品在线 | 中文字幕欧美人妻精品一区蜜臀 | 99精彩视频 | 久色亚洲 | 国产av成人一区二区三区高清 | 日韩久久久久久久久 | 大桥未久在线视频 | 国产视频a | 国产无毛片 | 污免费视频| 天天插综合网 | 激情视频网址 | 午夜精品久久久久久久蜜桃 | 国产精品一区二区免费看 | 亚洲经典三级 | 可以直接看的毛片 | a级片网址 | 成人黄色网页 | 中文字幕理论片 | 红桃视频一区二区三区免费 | 日本人体视频 | 另类图片亚洲色图 | 免费高清成人 | 亚洲精品国产精品国 | 国产精品系列在线 | 精品无码一区二区三区免费 | 欧美精品做受xxx性少妇 | 国产精品久久久久久亚洲调教 | 男男做的视频 | 香港三级网站 | 麻豆av在线播放 | www欧美精品| 视频福利在线观看 | 欧美第四页 | 欧美日韩国产在线观看 | 中国三级视频 | 一级中文片 | 日日麻批免费视频播放 | 成人黄色在线播放 |