NO IMAGE

這篇文章將介紹java中提高效率的一些方法。

1.迴圈條件中的複雜表示式應該獨立出來

在不做編譯優化的情況下,在迴圈中,迴圈條件會被反覆計算,如果不使用複雜表示式,而使迴圈條件值不變的話,程式將會執行的更快。

例子: 

import java.util.vector;
class cel {
void method (vector vector) {
for (int i = 0; i < vector.size (); i  )  // violation
; // ...
}
}

更正:

class cel_fixed {
void method (vector vector) {
int size = vector.size ()
for (int i = 0; i < size; i  )
; // ...
}
}

2.使用’system.arraycopy ()’代替通過來迴圈複製陣列 

‘system.arraycopy ()’ 要比通過迴圈來複制陣列快的多。        
例子: 

public class irb
{
void method () {
int[] array1 = new int [100];
for (int i = 0; i < array1.length; i  ) {
array1 [i] = i;
}
int[] array2 = new int [100];
for (int i = 0; i < array2.length; i  ) {
array2 [i] = array1 [i];                 // violation
}
}
}

   
更正: 

public class irb
{
void method () {
int[] array1 = new int [100];
for (int i = 0; i < array1.length; i  ) {
array1 [i] = i;
}
int[] array2 = new int [100];
system.arraycopy(array1, 0, array2, 0, 100);
}
}

3.使用移位操作來代替’a / b’操作,使用移位操作代替’a * b’ 

例子: 

public class sdiv {
public static final int num = 16;
public void calculate(int a) {
int div = a / 4;            // should be replaced with "a >> 2".
int div2 = a / 8;         // should be replaced with "a >> 3".
int temp = a / 3;
}
}

更正: 

public class sdiv {
public static final int num = 16;
public void calculate(int a) {
int div = a >> 2;  
int div2 = a >> 3;
int temp = a / 3;       // 不能轉換成位移操作
}
}

類似的,a*4,a*8可以用int mul = a << 2;    int mul2 = a << 3;代替,還有取餘運算a=a%8可以用a=a&7代替。但是要權衡可讀性問題。除法是整數運算中效率最低的,應該儘量避免。這裡補充下&運算的原理,如:

int a=129;
int b=128;
System.out.println(“a 和b 與的結果是:” (a&b));

“a”的值是129,轉換成二進位制就是10000001,而“b”的值是128,轉換成二進位制就是10000000。根據與運算子的運算規律,只有兩個位都是1,結果才是1,可以知道結果就是10000000,即128。

4.對於boolean值,避免不必要的等式判斷
將一個boolean值與一個true比較是一個恆等操作(直接返回該boolean變數的值). 移走對於boolean的不必要操作至少會帶來2個好處: 
1)程式碼執行的更快 (生成的位元組碼少了5個位元組); 
2)程式碼也會更加乾淨 。 

例子:

public class ueq
{
boolean method (string string) {
return string.endswith ("a") == true;   // violation
}
}

更正: 

class ueq_fixed
{
boolean method (string string) {
return string.endswith ("a");
}
}

5.合理使用string,stringBuffer和stringBuilder

(1).如果要操作少量的資料用 = String
(2).單執行緒操作字串緩衝區 下操作大量資料 = StringBuilder
(3).多執行緒操作字串緩衝區 下操作大量資料 = StringBuffer

通過StringBuffer的建構函式來設定他的初始化容量,可以明顯提升效能。 

6.不要在迴圈體中例項化變數

在迴圈體中例項化臨時變數將會增加記憶體消耗 
例子:         

import java.util.vector;
public class loop {
void method (vector v) {
for (int i=0;i < v.size();i  ) {
object o = new object();
o = v.elementat(i);
}
}
}

        
更正:         
在迴圈體外定義變數,並反覆使用         

import java.util.vector;
public class loop {
void method (vector v) {
object o;
for (int i=0;i<v.size();i  ) {
o = v.elementat(i);
}
}
}

7.在java Oracle的應用系統開發中,java中內嵌的SQL語言應儘量使用大寫形式,以減少Oracle解析器的解析負擔。 

8.array 陣列效率最高,但容量固定,無法動態改變,ArrayList容量可以動態增長,但犧牲了效率。 

9.不要使用 i % 2 == 1 來判斷是否是奇數,因為i為負奇數時不成立,請使用 i % 2 != 0 來判斷是否是奇數,或使用 高效式 (i & 1) != 0來判斷。(讓我想起了今年騰訊的筆試題)

10.貨幣單位計算時應該用最小單位,因為小數在java中是無法精確表示的,如:System.out.println(2.00 -1.10);//0.8999999999999999

11.int型別的溢位

我們計算一天中的微秒數: 
long microsPerDay = 24 * 60 * 60 * 1000 * 1000;// 正確結果應為:86400000000
System.out.println(microsPerDay);// 實際上為:500654080
問題在於計算過程中溢位了。這個計算式完全是以int運算來執行的,並且只有在運算完成之後,其結果才被提升為long,而此時已經太遲:計算已經溢位。 
解決方法使計算表示式的第一個因子明確為long型,這樣可以強制表示式中所有的後續計算都用long運算來完成,這樣結果就不會溢位: 
long microsPerDay = 24L * 60 * 60 * 1000 * 1000;

12.儘量使用final修飾符

帶有final修飾符的類是不可派生的。在JAVA核心API中,有許多應用final的例子,例如 java.lang.String。為String類指定final防止了使用者覆蓋length()方法。另外,如果一個類是final的,則該類所有方法都是final的。java編譯器會尋找機會內聯(inline)所有的final方法(這和具體的編譯器實現有關)。此舉能夠使效能平均提高 50%。 

13.用x ,x =1代替x=x 1能提高效率

14.條件判斷時將可能性大的放在前面

15.出於安全考慮,判斷語句應該將變數作為比較的物件

如if(a==3)代替為if(3==a)

16.氣泡排序的時候設定一個boolean型別的交換標記可以提高速度(排序好不用再遍歷)

例子:

package com.wws.yy;
import java.util.Random;
public class BubbleSortClient {
public static void main(String[] args) {
//構造資料
int[] arr = constructDataArray(15);
System.out.println("---------排序前-----------");
printArrayData(arr);
//氣泡排序
bubbleSort2(arr);
System.out.println("---------排序後-----------");
printArrayData(arr);
}
//構造資料
public static int[] constructDataArray(int length){
int[] arr = new int[length];
Random random = new Random();
for(int i=0;i<length;i  ){
arr[i] = random.nextInt(length);
}
return arr;
}
/**
* 氣泡排序方法----第一種方法
* @param arr
*/
public static  int[] bubbleSort(int[] arr){
for(int i=0; i<arr.length;i  ){
for(int j=i 1;j<arr.length;j  ){
if(arr[i] > arr[j]){
//交換資料
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
return arr;
}
/**
* 氣泡排序方法----第二種方法
* @param arr
*/
public static int[] bubbleSort2(int[] arr){
for(int i=0;i<arr.length;i  ){
for(int j=0;j<arr.length-1-i;j  ){
if(arr[j] > arr[j 1]){
//資料交換
int temp = arr[j];
arr[j] = arr[j 1];
arr[j 1] = temp;
}
}
}
return arr;
}
//列印資料
public static void printArrayData(int[] arr){
for(int d :arr){
System.out.print(d   "   ");
}
System.out.println();
}
}

優化後:

import java.util.Random;
public class BubbleSortClient {
public static void main(String[] args) {
//構造資料
int[] arr = constructDataArray(15);
System.out.println("---------排序前-----------");
printArrayData(arr);
//氣泡排序
bubbleSort4(arr);
System.out.println("---------排序後-----------");
printArrayData(arr);
}
//構造資料
public static int[] constructDataArray(int length){
int[] arr = new int[length];
Random random = new Random();
for(int i=0;i<length;i  ){
arr[i] = random.nextInt(length);
}
return arr;
}
/**
* 引入標誌位,預設為true
* 如果前後資料進行了交換,則為true,否則為false。如果沒有資料交換,則排序完成。
* @param arr
*/
public static int[] bubbleSort4(int[] arr){
boolean flag = true;
int n = arr.length;
while(flag){
flag = false;
for(int j=0;j<n-1;j  ){
if(arr[j] >arr[j 1]){
//資料交換
int temp = arr[j];
arr[j] = arr[j 1];
arr[j 1] = temp;
//設定標誌位
flag = true;
}
}
n--;
}
return arr;
}
//列印資料
public static void printArrayData(int[] arr){
for(int d :arr){
System.out.print(d   "   ");
}
System.out.println();
}
}