自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Java程序性能優(yōu)化之編程技巧總結(jié)

開(kāi)發(fā) 后端
程序的性能受代碼質(zhì)量的直接影響。在本文中,主要介紹一些代碼編寫(xiě)的小技巧和慣例,這些技巧有助于在代碼級(jí)別上提升系統(tǒng)性能。

 程序的性能受代碼質(zhì)量的直接影響。在本文中,主要介紹一些代碼編寫(xiě)的小技巧和慣例,這些技巧有助于在代碼級(jí)別上提升系統(tǒng)性能。

1、慎用異常

在Java軟件開(kāi)發(fā)中,經(jīng)常使用 try-catch 進(jìn)行錯(cuò)誤捕獲,但是,try-catch 語(yǔ)句對(duì)系統(tǒng)性能而言是非常糟糕的。雖然在一次 try-catch中,無(wú)法察覺(jué)到它對(duì)性能帶來(lái)的損失,但是,一旦try-catch被應(yīng)用于循環(huán)之中,就會(huì)給系統(tǒng)性能帶來(lái)極大的傷害。

以下是一段將try-catch應(yīng)用于for循環(huán)內(nèi)的示例 

  1. public void test() {         
  2.        int a = 0;         
  3.        for (int i = 0; i < 1000000; i++) {             
  4.             try { 
  5.                 a = a + 1; 
  6.                 System.out.println(i); 
  7.             } catch (Exception e) { 
  8.                 e.printStackTrace(); 
  9.             } 
  10.         } 
  11.     }  

這段代碼我運(yùn)行時(shí)間是 27211 ms。如果將try-catch移到循環(huán)體外,那么就能提升系統(tǒng)性能,如下代碼 

  1. public void test() {         
  2.     int a = 0;         
  3.         try {             
  4.             for (int i = 0; i < 1000000; i++) { 
  5.                 a = a + 1; 
  6.                 System.out.println(i); 
  7.             } 
  8.         } catch (Exception e) { 
  9.             e.printStackTrace(); 
  10.         } 
  11.     }  

運(yùn)行耗時(shí) 15647 ms??梢?jiàn)tyr-catch對(duì)系統(tǒng)性能的影響。

2、使用局部環(huán)境

調(diào)用方法時(shí)傳遞的參數(shù)以及在調(diào)用中創(chuàng)建的臨時(shí)變量都保存在棧(Stack)中,速度較快。其他變量,如靜態(tài)變量、實(shí)例變量等,都在堆(Heap)中創(chuàng)建,速度較慢。

下面是一段測(cè)試用例 

  1. //   private static int a = 0; 
  2.     public static void main(String[] args) {         
  3.        int a = 0;         
  4.        long start = System.currentTimeMillis();         
  5.        for (int i = 0; i < 1000000; i++) { 
  6.             a = a + 1; 
  7.             System.out.println(i); 
  8.         } 
  9.         System.out.println(System.currentTimeMillis() - start); 
  10.     }  

運(yùn)行結(jié)果很明顯,使用靜態(tài)變量耗時(shí)15677ms,使用局部變量耗時(shí)13509ms。由此可見(jiàn),局部變量的訪問(wèn)速度高于類的成員變量。

3、位運(yùn)算代替乘除法

在所有的運(yùn)算中,位運(yùn)算是最為高效的。因此,可以嘗試使用位運(yùn)算代替部分算術(shù)運(yùn)算,來(lái)提高系統(tǒng)的運(yùn)行速度。

比如在HashMap的源碼中使用了位運(yùn)算 

  1. static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16  
  2. static final int MAXIMUM_CAPACITY = 1 << 30;  

對(duì)于整數(shù)的乘除運(yùn)算優(yōu)化 

  1. a*=2  
  2. a/=2  

用位運(yùn)算可以寫(xiě)為 

  1. a<<=1a>>=1 

4、替換switch

關(guān)鍵字 switch 語(yǔ)句用于多條件判斷, switch 語(yǔ)句的功能類似于 if-else 語(yǔ)句,兩者性能也差不多。因此,不能說(shuō) switch 語(yǔ)句會(huì)降低系統(tǒng)的性能。但是,在絕大部分情況下,switch 語(yǔ)句還是有性能提升空間的。

來(lái)看下面的例子: 

  1. public static void main(String[] args) {         
  2.         long start = System.currentTimeMillis();         
  3.         int re = 0;         
  4.         for (int i = 0;i<1000000;i++){ 
  5.             re = switchInt(i); 
  6.             System.out.println(re); 
  7.         } 
  8.         System.out.println(System.currentTimeMillis() - start+"毫秒");//17860 
  9.     }     
  10.     public static int switchInt(int z){         
  11.            int i = z%10+1;         
  12.            switch (i){             
  13.            case 1:return 3;             
  14.            case 2:return 6;             
  15.            case 3:return 7;             
  16.            case 4:return 8;             
  17.            case 5:return 10;             
  18.            case 6:return 16;             
  19.            case 7:return 18;             
  20.            case 8:return 44;             
  21.            default:return -1; 
  22.      } 
  23.   }  

就分支邏輯而言,這種 switch 模式的性能并不差。但是如果換一種新的思路替代switch,實(shí)現(xiàn)相同的程序功能,性能就能有很大的提升空間。 

  1. public static void main(String[] args) {         
  2.         long start = System.currentTimeMillis();         
  3.         int re = 0;         
  4.         int[] sw = new int[]{0,3,6,7,8,10,16,18,44};         
  5.         for (int i = 0;i<1000000;i++){ 
  6.             re = arrayInt(sw,i); 
  7.             System.out.println(re); 
  8.         } 
  9.         System.out.println(System.currentTimeMillis() - start+"毫秒");//12590 
  10.     }     
  11.     public static int arrayInt( 
  12.         int[] sw,int z){         
  13.         int i = z%10+1;         
  14.         if (i>7 || i<1){             
  15.            return -1; 
  16.         }else {             
  17.            return sw[i]; 
  18.         } 
  19.     }  

以上代碼使用全新的思路,使用一個(gè)連續(xù)的數(shù)組代替了 switch 語(yǔ)句。因?yàn)閷?duì)數(shù)據(jù)的隨機(jī)訪問(wèn)是非??斓?,至少好于 switch 的分支判斷。通過(guò)實(shí)驗(yàn),使用switch的語(yǔ)句耗時(shí)17860ms,使用數(shù)組的實(shí)現(xiàn)只耗時(shí)12590ms,提升了5s多。在軟件開(kāi)發(fā)中,換一種思路可能會(huì)取得更好的效果,比如使用數(shù)組替代switch語(yǔ)句就是就是一個(gè)很好的例子。

5、一維數(shù)組代替二維數(shù)組

由于數(shù)組的隨機(jī)訪問(wèn)的性能非常好,許多JDK類庫(kù),如ArrayList、Vector等都是使用了數(shù)組作為其數(shù)組實(shí)現(xiàn)。但是,作為軟件開(kāi)發(fā)人員也必須知道,一位數(shù)組和二維數(shù)組的訪問(wèn)速度是不一樣的。一位數(shù)組的訪問(wèn)速度要優(yōu)于二維數(shù)組。因此,在性能敏感的系統(tǒng)中要使用二維數(shù)組的,可以嘗試通過(guò)可靠地算法,將二維數(shù)組轉(zhuǎn)為一維數(shù)組再進(jìn)行處理,以提高系統(tǒng)的響應(yīng)速度。

6、提取表達(dá)式

在軟件開(kāi)發(fā)過(guò)程中,程序員很容易有意無(wú)意讓代碼做一些“重復(fù)勞動(dòng)”,在大部分情況下,由于計(jì)算機(jī)的告訴運(yùn)行,這些“重復(fù)勞動(dòng)”并不會(huì)對(duì)性能構(gòu)成太大的威脅,但若將系統(tǒng)性能發(fā)揮到***,提取這些“重復(fù)勞動(dòng)”相當(dāng)有意義。

來(lái)看下面的測(cè)試用例: 

  1. @Test     
  2.    public void test(){         
  3.         long start = System.currentTimeMillis(); 
  4.         ArrayList list = new ArrayList();         
  5.         for (int i = 0;i<100000;i++){ 
  6.             System.out.println(list.add(i)); 
  7.         }        //以上是為了做準(zhǔn)備 
  8.         for (int i = 0;i<list.size();i++){ 
  9.             System.out.println(list.get(i)); 
  10.         } 
  11.         System.out.println(System.currentTimeMillis() - start);//5444 
  12.     }  

如果我們把list.size()方法提取出來(lái),優(yōu)化后的代碼如下: 

  1. @Test     
  2.    public void test(){         
  3.        long start = System.currentTimeMillis(); 
  4.        ArrayList list = new ArrayList();         
  5.        for (int i = 0;i<100000;i++){ 
  6.            System.out.println(list.add(i)); 
  7.        }        //以上是為了做準(zhǔn)備 
  8.        int n = list.size();         
  9.        for (int i = 0;i<n;i++){ 
  10.            System.out.println(list.get(i)); 
  11.        } 
  12.        System.out.println(System.currentTimeMillis() - start);//3514 
  13.    }  

在我的機(jī)器上,前者耗時(shí)5444ms,后者耗時(shí)3514ms,相差2s左右,可見(jiàn),提取重復(fù)的操作是相當(dāng)有意義的。

7、展開(kāi)循環(huán)

與前面所介紹的優(yōu)化技巧略有不同,筆者認(rèn)為展開(kāi)循環(huán)是一種在極端情況下使用的優(yōu)化手段,因?yàn)檎归_(kāi)循環(huán)很可能會(huì)影響代碼的可讀性和可維護(hù)性,而這兩者對(duì)軟件系統(tǒng)來(lái)說(shuō)也是極為重要的。但是,當(dāng)性能問(wèn)題成為系統(tǒng)主要矛盾時(shí),展開(kāi)循環(huán)絕對(duì)是一種值得嘗試的技術(shù)。

8、布爾運(yùn)算代替位運(yùn)算

雖然位運(yùn)算的速度遠(yuǎn)遠(yuǎn)高于算術(shù)運(yùn)算,但是在條件判斷時(shí),使用位運(yùn)算替代布爾運(yùn)算卻是非常錯(cuò)誤的選擇。

在條件判斷時(shí),Java會(huì)對(duì)布爾運(yùn)算做相當(dāng)充分的優(yōu)化。假設(shè)有表達(dá)式 a,b,c 進(jìn)行布爾運(yùn)算“a&&b&&c” ,根據(jù)邏輯與的特點(diǎn),只要在整個(gè)布爾表達(dá)式中有一項(xiàng)返回false,整個(gè)表達(dá)式就返回false,因此,當(dāng)表達(dá)式a為false時(shí),該表達(dá)式將立即返回 false ,而不會(huì)再去計(jì)算表達(dá)式b 和c。同理,當(dāng)計(jì)算表達(dá)式為“a||b||c”時(shí),也是一樣。

若使用位運(yùn)算(按位與”&“、按位或”|“)代替邏輯與和邏輯或,雖然位運(yùn)算本身沒(méi)有性能問(wèn)題,但是位運(yùn)算總是要將所有的子表達(dá)式全部計(jì)算完成后,再給出最終結(jié)果。因此,從這個(gè)角度來(lái)說(shuō),使用位運(yùn)算替代布爾運(yùn)算會(huì)使系統(tǒng)進(jìn)行很多無(wú)效計(jì)算。

9、使用arrayCopy()

數(shù)組復(fù)制是一項(xiàng)使用頻率很高的功能,JDK中提供了一個(gè)高效的API來(lái)實(shí)現(xiàn)它:

如果在應(yīng)用程序需要進(jìn)行數(shù)組復(fù)制,應(yīng)該使用這個(gè)函數(shù),而不是自己實(shí)現(xiàn)。

方法代碼: 

  1. public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);  

它的用法是將源數(shù)組 src 從索引 srcPos 處復(fù)制到目標(biāo)數(shù)組 dest 的 索引destPos處,復(fù)制的長(zhǎng)度為 length。

System.arraycopy() 方法是 native 方法,通常 native 方法的性能要優(yōu)于普通的方法。僅出于性能考慮,在軟件開(kāi)發(fā)中,盡可能調(diào)用 native 方法。

10、使用Buffer進(jìn)行I/O流操作

除NIO外,使用 Java 進(jìn)行 I/O操作有兩種基本方法:

  1. 使用基于InputStream 和 OutputStream 的方式;(字節(jié)流)
  2. 使用 Writer 和 Reader。(字符流)

無(wú)論使用哪種方式進(jìn)行文件 I/O,如果能合理地使用緩沖,就能有效的提高I/O的性能。 

 

11、使用clone()代替new

在Java中新建對(duì)象實(shí)例最常用的方法是使用 new 關(guān)鍵字。JDK對(duì) new 的支持非常好,使用 new 關(guān)鍵字創(chuàng)建輕量級(jí)對(duì)象時(shí),速度非常快。但是,對(duì)于重量級(jí)對(duì)象,由于對(duì)象在構(gòu)造函數(shù)中可能會(huì)進(jìn)行一些復(fù)雜且耗時(shí)的操作,因此,構(gòu)造函數(shù)的執(zhí)行時(shí)間可能會(huì)比較長(zhǎng)。導(dǎo)致系統(tǒng)短期內(nèi)無(wú)法獲得大量的實(shí)例。為了解決這個(gè)問(wèn)題,可以使用Object.clone() 方法。

Object.clone() 方法可以繞過(guò)構(gòu)造函數(shù),快速?gòu)?fù)制一個(gè)對(duì)象實(shí)例。但是,在默認(rèn)情況下,clone()方法生成的實(shí)例只是原對(duì)象的淺拷貝。

這里不得不提Java只有值傳遞了,關(guān)于這點(diǎn),我的理解是基本數(shù)據(jù)類型引用的是值,普通對(duì)象引用的也是值,不過(guò)這個(gè)普通對(duì)象引用的值其實(shí)是一個(gè)對(duì)象的地址。代碼示例: 

  1. int i = 0; int j = i; //i的值是0  
  2. User user1 = new User();  
  3. User user2 = user1; //user1值是new User()的內(nèi)存地址  

如果需要深拷貝,則需要重新實(shí)現(xiàn) clone() 方法。下面看一下ArrayList實(shí)現(xiàn)的clone()方法:

 

  1. public Object clone() {         
  2.        try { 
  3.             ArrayList<?> v = (ArrayList<?>) super.clone(); 
  4.             v.elementData = Arrays.copyOf(elementData, size); 
  5.             v.modCount = 0;             
  6.             return v; 
  7.         } catch (CloneNotSupportedException e) {             
  8.             // this shouldn't happen, since we are Cloneable 
  9.             throw new InternalError(e); 
  10.         } 
  11.     } 

 

在ArrayList的clone()方法中,首先使用 super.clone() 方法生成一份淺拷貝對(duì)象。然后拷貝一份新的elementData數(shù)組讓新的ArrayList去引用。使克隆后的ArrayList對(duì)象與原對(duì)象持有不同的引用,實(shí)現(xiàn)了深拷貝。

12、靜態(tài)方法替代實(shí)例方法

使用 static 關(guān)鍵字描述的方法為靜態(tài)方法。在Java中,由于實(shí)例方法需要維護(hù)一張類似虛函數(shù)表的結(jié)構(gòu),以實(shí)現(xiàn)對(duì)多態(tài)的支持。與靜態(tài)方法相比,實(shí)例方法的調(diào)用需要更多的資源。因此,對(duì)于一些常用的工具類方法,沒(méi)有對(duì)其進(jìn)行重載的必要,那么將它們聲明為 static,便可以加速方法的調(diào)用。同時(shí),調(diào)用 static 方法不需要生成類的實(shí)例。比調(diào)用實(shí)例方法更為方便、易用。

責(zé)任編輯:龐桂玉 來(lái)源: java版web項(xiàng)目
相關(guān)推薦

2019-10-17 10:10:23

優(yōu)化Web前端

2009-06-15 09:47:12

Java程序內(nèi)存溢出

2017-12-23 14:38:41

Android編程開(kāi)發(fā)優(yōu)化

2009-07-29 11:33:14

ASP.NET技巧ASP.NET應(yīng)用程序

2019-02-25 07:07:38

技巧React 優(yōu)化

2009-01-08 19:11:39

服務(wù)器應(yīng)用程序SQL Server

2010-11-15 16:20:33

Oracle系統(tǒng)優(yōu)化

2009-01-08 19:14:37

服務(wù)器應(yīng)用程序SQL Server

2013-12-17 17:05:20

iOS性能優(yōu)化

2011-07-11 15:26:49

性能優(yōu)化算法

2019-07-18 12:40:49

Java編程語(yǔ)言性能優(yōu)化

2022-07-20 07:45:15

多線程程序性能

2011-06-14 13:48:07

性能優(yōu)化工具

2011-06-14 11:14:10

性能優(yōu)化代碼

2011-06-14 14:32:46

性能優(yōu)化

2011-06-14 14:17:23

性能優(yōu)化系統(tǒng)層次

2016-12-28 11:23:59

優(yōu)化iOS程序性

2010-04-21 12:49:57

Oracle性能

2010-08-10 13:58:00

Flex性能測(cè)試

2011-09-29 09:50:44

JavaScript
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)