search
尋找貓咪~QQ 地點 桃園市桃園區 Taoyuan , Taoyuan

14個java編程技巧(最佳實踐的初學者)

1.return 一個空的集合,而不是 null

如果一個程序返回一個沒有任何值的集合,請確保一個空集合返回,而不是空元素。這樣你就不用去寫一大堆 」if else」 判斷null元素。

Java 的標準庫設計者已經在 Collections 類中放了一個空的 List 常量 EMPTY_LIST,除此之外,還有 EMPTY_MAP, EMPTY_SET,真是貼心。

2. 小心使用 String

因為字元串相加或者拼接的方式都會在對象池中查找字元串是否存在,如果不存在則創建,這樣在拼接的過程中會產生大量中間過程的字元串,佔用內存資源。StringBuilder效率優於StringBuffer,但是StringBuffer線程安全。

另外,在實例化一個字元串對象,構造函數應該避免發生直接實例化,例如:

3. 避免不必要的對象

一個最昂貴的操作(在內存利用率)是java對象的創建。因此,建議只在必要時創建或初始化對象。下面的代碼給出了一個例子:

4.Array 和ArrayList 選擇

ArrayList和Array是我們在實際編程中經常使用的容器,而且因為ArrayList相當於動態化的數組,所以它們之間有太多的相似,以至於我們在選擇哪種來存儲元素的時候,會有小小的迷惑,他們都有註解的優缺點,選擇真的取決於你的真實場景。

4.1.Array 有固定大小但 ArrayList 的大小不同。

由於Array 的大小是固定的,在Array 類型變數聲明的時候,內存被分配。因此,Array 是非常快的。另一方面, 使用ArrayList的最大缺點就是當我們添加新的元素的時候,它是先檢查內部數組的容量是否足夠,如果不夠,它會創建一個容量為原來數組兩倍的新數組,���后將所有元素複製到新數組裡,接著拋掉舊數組。

這點真的很麻煩,因為每次都要這麼搞,尤其是元素足夠多的時候,這就真的是既影響內存又影響效率的問題,但通過單獨測試它們的運行時間,發現其實差不多,最大的影響就是如果是有其他代碼也需要使用到內存,那麼Array依然不變,但是ArrayList就會變得慢多,相同情況下所花的時間是Array的四倍多(實際情況是遠遠不止)。

4.2.這是添加或刪除元素從ArrayList 比Array更容易。

4.3.數組可以多維但ArrayList只有一個維度。

4.4.ArrayList因為內部是一個數組,所以它是可以轉化為數組的。

4.5 兩者的適用場合:

List list = new ArrayList;

雖然我們想要的確實是ArrayList而不是list,但是我們知道,父類是可以獲得子類的引用並且使用子類的方法,所以這樣我們就能同時使用List和ArrayList的方法而不用害怕出錯了。

首先,一個重要的約束就是,List的聲明區域一般是在main方法里(當然靜態list也可以,但是我們一般使用的時候都只是當做存儲元素的臨時容器),而Array是可以在外部進行聲明的,這時它就是全局數組。

所以,單看這點,它們的使用已經有區別,如果想要保存一些在整個程序運行期間都會存在而且不變的數據,我們可以將它們放進一個全局數組裡,但是如果我們單純只是想要以數組的形式保存數據,方便我們進行查找,那麼,我們就選擇ArrayList。

而且還有一個地方是必須知道的,就是如果我們需要對元素進行頻繁的移動或刪除,或者是處理的是超大量的數據,那麼,使用ArrayList就真的不是一個好的選擇,因為它的效率很低,使用數組進行這樣的動作就很麻煩,那麼,我們可以考慮選擇LinkedList。

5.用try catch的時候,要加finally嗎?

考慮下面的代碼片斷

運行結果:

在Finally代碼塊中

在Finally代碼塊中

在Finally代碼塊中

在Finally代碼塊中

在Try內部代碼塊,退出不執行Finally代碼塊

在運行代碼前,它看起來像要列印 」在Finally代碼塊中「 5次。但是執行的結果只有4次。第五次列印的結果是 」在Try內部代碼塊,退出不執行Finally代碼塊「。

關於 Java 虛擬機是如何編譯 finally 語句塊的問題,有興趣的讀者可以參考《 The JavaTM Virtual Machine Specification, Second Edition 》中 7.13 節 Compiling finally。那裡詳細介紹了 Java 虛擬機是如何編譯 finally 語句塊。實際上,Java 虛擬機會把 finally 語句塊作為 subroutine(對於這個 subroutine 不知該如何翻譯為好,乾脆就不翻譯了,免得產生歧義和誤解。)直接插入到 try 語句塊或者 catch 語句塊的控制轉移語句之前。但是,還有另外一個不可忽視的因素,那就是在執行 subroutine(也就是 finally 語句塊)之前,try 或者 catch 語句塊會保留其返回值到本地變數表(Local Variable Table)中。待 subroutine 執行完畢之後,再恢復保留的返回值到操作數棧中,然後通過 return 或者 throw 語句將其返回給該方法的調用者(invoker)。

將上面代碼修改如下:

運行結果:

在Try內部代碼塊,退出不執行Finally代碼塊

在Try內部代碼塊,退出不執行Finally代碼塊

在Try內部代碼塊,退出不執行Finally代碼塊

在Try內部代碼塊,退出不執行Finally代碼塊

在Try內部代碼塊,退出不執行Finally代碼塊

總結:

這裡就不過多的去具體分析整個過程有興趣的朋友可找資料了解整個過程,一個小小的、看似簡單的 finally 語句塊背後居然隱藏了這麼多玄機。看來,我們平時還是應該認真的閱讀 Java 相關的基礎文檔,比如:Java 語言規範、Java 虛擬機規範等,很多棘手的問題都可以從中得到答案。只有真正的吃透了基礎知識,才能達到運用自如的境界!

1> try、catch、finally語句中,在如果try語句有return語句,則返回的之後當前try中變數此時對應的值,此後對變數做任何的修改,都不影響try中return的返回值

2> 如果finally塊中有return 語句,則返回try或catch中的返回語句忽略。

3 >如果finally塊中拋出異常,則整個try、catch、finally塊中拋出異常

所以使用try、catch、finally語句塊中需要注意的是

1> 盡量在try或者catch中使用return語句。通過finally塊中達到對try或者catch返回值修改是不可行的。

2 >finally塊中避免使用return語句,因為finally塊中如果使用return語句,會顯示的消化掉try、catch塊中的異常信息,屏蔽了錯誤的發生

3 >finally塊中避免再次拋出異常,否則整個包含try語句塊的方法回拋出異常,並且會消化掉try、catch塊中的異常

6.奇數判斷

看看下面的代碼行,並確定如果他們可以用來精確地識別一個給定的數字是否是奇數?

奇數可以被定義為被2整除餘數為1的整數。表達式 num% 2 計算的是 num整除 2 時所產生的餘數,因此看起來這個程序應該能夠正確運轉。遺憾的是,它不能;它在四分之一的時間裡返回的都是錯誤的答案。

為什麼是四分之一?因為在所有的 int 數值中,有一半都是負數,而 isOdd 方法對於對所有負奇數的判斷都會失敗。在任何負整數上調用該方法都回返回 false ,不管該整數是偶數還是奇數。

這是 Java 對取余操作符(%)的定義所產生的後果。該操作符被定義為對於所有的 int 數值 a 和所有的非零 int 數值b,都滿足下面的恆等式:

(a / b) * b + (a % b) == a

現在進行修改如下:

使用此代碼,不僅是解決了奇數的負的問題,而且這個代碼也高度優化。因為,算術和邏輯運算的速度更快,比除法和乘法,結果取得了更快。

7. 單引號和雙引號之間的區別

嘗試運行上面的程序。這個程序演示了一個死鎖。這種死鎖的產生是因為兩個線程都在等待其他線程所抓取的資源。他們都不在任何一個版本。從代碼,似乎還「HaHa」是回來了,但它實際上返回ha169。原因是,如果使用雙引號,字元串對待,但在單引號的情況下,字元自動轉換為int型,進行計算。

8. 通過簡單的技巧避免內存泄漏

內存泄漏經常會導致軟體的性能退化。因為,java自動管理內存,開發商沒有太多的控制。但仍有一些標準的做法,可以用來防止內存泄漏。

當查詢完成時,總是釋放資料庫連接。

盡量使用 Finally 塊。

釋放存儲在靜態表中的實例。

9. 避免死鎖

死鎖出現的原因有很多。避免死鎖不是一句話就能解決的。通常來說,當某個同步對象在等待另一個同步對象所擁有的資源上的鎖時,便會產生死鎖。

試著運行下下面的程序。它會告訴你什麼是死鎖。這個死鎖是由於兩個線程都在等待對方所擁有的資源,因此會產生死鎖。它們會一直等待,沒有誰會先放手。

運行結果:

Addition Thread: 13

Subtraction Thread: 7

Holding First Lock…

Holding Second Lock…

Addition Thread: Waiting for AddLock…

Subtraction Thread: Waiting for SubLock…

但如果調用的順序變一下的話,死鎖的問題就解決了。

將 MySubtractionThread中的線程加鎖順序調換再看看

運行結果:

Addition Thread: 13

Holding First Lock…

Addition Thread: Waiting for AddLock…

Threads: Holding Add and Sub Locks…

Subtraction Thread: 7

Holding Second Lock…

Subtraction Thread: Waiting for SubLock…

Threads: Holding Add and Sub Locks…

三種用於避免死鎖的技術:

1>加鎖順序

2>加鎖時限

3>死鎖檢測

一個更好的方案是給這些線程設置優先順序,讓一個(或幾個)線程回退,剩下的線程就像沒發生死鎖一樣繼續保持著它們需要的鎖。如果賦予這些線程的優先順序是固定不變的,同一批線程總是會擁有更高的優先順序。為避免這個問題,可以在死鎖發生的時候設置隨機的優先順序。

10.JAVA運行內存的設置

一些java應用程序可以被高度的CPU密集型以及他們需要很多內存。這樣的應用程序通常運行速度慢,因為內存高的要求。所以,我們可以在相關的配置文件中進行修改調整內存大小。

Xms = 設置內存初始化的大小

Xmx = 設置最大能夠使用內存的大小

XX:PermSize =初始大小,將分配給JVM的啟動過程

XX:MaxPermSize = 最大尺寸可以分配JVM的啟動過程

11. 如何在java時間操作

有java時間兩種標準方法:

System.currentTimeMillis、System.nanoTime

平時產生隨機數時我們經常拿時間做種子,比如用System.currentTimeMillis的結果,但是在執行一些循環中使用了System.currentTimeMillis,那麼每次的結果將會差別很小,甚至一樣,因為現代的計算機運行速度很快。後來看到java中產生隨機數函數以及線程池中的一些函數使用的都是System.nanoTime。

>System.currentTimeMillis返回的是從1970.1.1 UTC 零點開始到現在的時間,精確到毫秒,平時我們可以根據System.currentTimeMillis來計算當前日期,星期幾等,可以方便的與Date進行轉換,

> System.nanoTime提供相對精確的計時,但是不能用他來計算當前日期,

所以在使用中,我們可以根據我們具體的目的去正確的選擇他們。

12. Float 和Double的選擇

double應該比float更好用,原因:

大多數處理器需要幾乎相同數量的處理時間來執行浮點和雙運算的操作。在相同數量的計算時間雙提供了更高的精度。

13. Java的乘方運算

java提供了兩個方法:

Multiplication:乘法

pow(double base, double exponent):(base的exponent次方)

math.pow只應在必要時使用,像指數是一個分數。Math.pow方法通常慢300-600倍的速度比乘法。

14. 如何處理空指針異常

空指針異常在java中是很常見的。當我們嘗試調用一個空對象引用的方法時,這個異常會發生。例如:

如果在上面的例子中,如果得到一個NullPointerException異常,然後學校 是null 或liststudentsnull。有個好注意你可以提早將異常拋出,通過提早拋出異常(又���"迅速失敗"),異常得以清晰又準確堆棧信息立即反映出什麼出了錯(提供了非法參數值),為什麼出錯(文件名不能為空值),以及哪裡出的錯,菜鳥和高手都可能犯的一個錯是,在程序有能力處理異常之前就捕獲它。Java編譯器通過要求檢查出的異常必須被捕獲或拋出而間接助長了這種行為。自然而然的做法就是立即將代碼用try塊包裝起來,並使用catch捕獲異常,以免編譯器報錯。



熱門推薦

本文由 yidianzixun 提供 原文連結

寵物協尋 相信 終究能找到回家的路
寫了7763篇文章,獲得2次喜歡
留言回覆
回覆
精彩推薦