7.Practical Java_实践 28-45:性能

 

实践 39:不要使用 Enumeration或 Iterato r来遍历 Vector
Java供遍历vector元素的数种办法:
1. Iterator(选代器)
2. ListIerator(list迭代器)
3. Enumeration(枚举器)
4. get()函数(取值函数, getter)

import java.util.Enumeration;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.Vector;

public class LoopVector {
    public int enumVec(Vector vec) {
        int total = 0;
        Enumeration enums =  vec.elements();
        while(enums.hasMoreElements()) {
            total += ((Integer)enums.nextElement()).intValue();
        }
        return total;
    }

    public int iterVec(Vector vec) {
        int total = 0;
        Iterator iter = vec.iterator();
        while(iter.hasNext()) {
            total += ((Integer) iter.next()).intValue();
        }
        return total;
    }

    public int listIterVec(Vector vec) {
        int total = 0;
        ListIterator iter = vec.listIterator();
        while(iter.hasNext()) {
            total += ((Integer)iter.next()).intValue();
        }
        return total;
    }

    public int forVec(Vector vec) {
        int total = 0;
        int size = vec.size();
        for (int i = 0; i < size; i++) {
            total += ((Integer) vec.get(i)).intValue();
        }
        return total;
    }

    public static void main(String[] args) {
        int VEC_SIZE = 100000;
        Vector<Integer> vec = new Vector<>(VEC_SIZE);
        for (int i = 1; i <= VEC_SIZE; i++) {
            vec.add(i);
        }

        long startTimer = 0;
        long endTimer = 0;
        int res = 0;

        LoopVector lv = new LoopVector();

        startTimer = System.currentTimeMillis();
        res = lv.enumVec(vec);
        endTimer = System.currentTimeMillis();
        System.out.println("invoke enumVec: res = " + res + ", cost=" + (endTimer-startTimer));

        startTimer = System.currentTimeMillis();
        res = lv.iterVec(vec);
        endTimer = System.currentTimeMillis();
        System.out.println("invoke iterVec: res = " + res + ", cost=" + (endTimer-startTimer));

        startTimer = System.currentTimeMillis();
        res = lv.listIterVec(vec);
        endTimer = System.currentTimeMillis();
        System.out.println("invoke listIterVec: res = " + res + ", cost=" + (endTimer-startTimer));

        startTimer = System.currentTimeMillis();
        res = lv.forVec(vec);
        endTimer = System.currentTimeMillis();
        System.out.println("invoke forVec: res = " + res + ", cost=" + (endTimer-startTimer));
    }
}

传入同一个vector,以上四个函数完成相同的任务.返回一样的结果。其中三个函数有不同的性能: Iterator版和 ListIterator版的性能大致相同, Enumeration版大约快 l 2%。至于采用Vectorget()的标准循环版本,比其他三个函数快 29%—34%.

invoke enumVec: res = 705082704, cost=7
invoke iterVec: res = 705082704, cost=8
invoke listIterVec: res = 705082704, cost=9
invoke forVec: res = 705082704, cost=5


实践 40:使用 System.arraycopy()来复制 arrays
copyAray2()比copyArray1()体积小,因为它毕竟是使用函数调用来完成工作,而非使用 inline方式。由于 copyArray2()调用的 System.arraycopy()是以本机函数( native method)实现的,因此它的执行速度更快。由于它是本机函数,所以它可以直接、
高效地移动[原始 array]的内在内容到[目标 array]。这个动作之快速足以消减本机函数的调用代价,明显比一般Java代码快得多。但也由于它是一个本机函数( nativemethod) ,所以这个调用动作的执行速度在不同的平台上有所不同。

public class CopyArrayTest {
    public void copyArray1(int[] src, int[] dest) {
        int size = src.length;
        for (int i = 0; i < size; i++) {
            dest[i] = src[i];
        }
    }
    public void copyArray2(int[] src, int[] dest) {
        int size = src.length;
        System.arraycopy(src, 0, dest, 0, size);
    }

    public static void main(String[] args) {
        int ARRAY_SIZE = 100000000;
        int[] src = new int[ARRAY_SIZE];
        int[] dest1 =  new int[ARRAY_SIZE];
        int[] dest2 =  new int[ARRAY_SIZE];

        for (int i = 0; i < ARRAY_SIZE; i++) {
            src[i] = i;
            dest1[i] = 0;
            dest2[i] = 0;
        }

        CopyArrayTest cat = new CopyArrayTest();
        long startTimer = 0;
        long endTimer = 0;

        startTimer = System.currentTimeMillis();
        cat.copyArray1(src, dest1);
        endTimer = System.currentTimeMillis();
        System.out.println("copyArray1, dest[ARRAY_SIZE-1] = " + dest1[ARRAY_SIZE-1] + ", timer = " + (endTimer - startTimer));

        startTimer = System.currentTimeMillis();
        cat.copyArray2(src, dest2);
        endTimer = System.currentTimeMillis();
        System.out.println("copyArray2, dest[ARRAY_SIZE-1] = " + dest2[ARRAY_SIZE-1] + ", timer = " + (endTimer - startTimer));

    }
}

/*
copyArray1, dest[ARRAY_SIZE-1] = 99999999, timer = 97
copyArray2, dest[ARRAY_SIZE-1] = 99999999, timer = 87
*/

实践41:优先使用 array,然后才考虑Vector和ArrayList
Vector和 ArrayList都采用 array作为底部设施,所以当这些 classes调整自身大小的时候,会创建一个新的 array, 然后将所有元素从原先的 array复制到新的 array中, 而后便可加入原本放不下的新元素了。
Vector和 ArrayList还有另一个不太起眼的副作用。 无论什么时候, 如果要从它们之中移除 ( removed)一个元素,所有[下标大于被删除元素]者都需要向前(向着起始处)移动一格。这样可以使得底部的 array不至于留下[空洞](holes)。

Vector的 get()是 synchronized,可以自动调整;----速度最慢
ArrayList的get()是unsynchronized,可以自动调整;----速度次之
Array不可以自动调整;-------速度最快
 

import java.util.ArrayList;
import java.util.Vector;

public class LoopArray {
    public void iterateArray(int[] arr) {
        int size = arr.length;
        int j;
        for (int i = 0; i < size; i++) {
            j = arr[i];
        }
    }
    public void iteratorVector(Vector vec) {
        int size = vec.size();
        Object j;
        for (int i = 0; i < size; i++) {
            j = vec.get(i);
        }
    }
    public void iterateArrayList(ArrayList alt) {
        int size = alt.size();
        Object j;


        for (int i = 0; i < size; i++) {
            j = alt.get(i);
        }
    }

    public static void main(String[] args) {
        int SIZE=1000000;

        int[] arr = new int[SIZE];
        Vector vec = new Vector(SIZE);
        ArrayList alt = new ArrayList(SIZE);

        for (int i = 0; i < SIZE; i++) {
            arr[i] = i;
            vec.add(i);
            alt.add(i);
        }

        long startTimer = 0;
        long endTimer = 0;
        LoopArray la = new LoopArray();

        startTimer = System.currentTimeMillis();
        la.iterateArray(arr);
        endTimer = System.currentTimeMillis();
        System.out.println("iterateArray timer = " + (endTimer - startTimer));

        startTimer = System.currentTimeMillis();
        la.iteratorVector(vec);
        endTimer = System.currentTimeMillis();
        System.out.println("iteratorVector timer = " + (endTimer - startTimer));

        startTimer = System.currentTimeMillis();
        la.iterateArrayList(alt);
        endTimer = System.currentTimeMillis();
        System.out.println("iterateArrayList timer = " + (endTimer - startTimer));
    }
}

/*
iterateArray timer = 3
iteratorVector timer = 8
iterateArrayList timer = 4
*/

实践 42:尽可能复用(reuse)对象
创建对象,代价不菲(参见实践32) ,因此你应该尽量减少创建次数。复用既有对象,而不重新创建一个。
 

class Employee {
    private String name;
    private String title;
    private int salary;

    public Employee() {}
    public Employee(String name, String title, int salary) {
        this.name  = name;
        this.title = title;
        this.salary = salary;
    }
    public void reinitialize(String name, String title, int salary) {
        this.name  = name;
        this.title = title;
        this.salary = salary;
    }
    public String getName() {return this.name;}
    public void setName(String name) {this.name = name;}
    public String getTitle() {return this.title;}
    public void setTitle(String title) {this.title = title;}
    public int getSalary() {return this.salary;}
    public void setSalary(int salary) {this.salary = salary;}
}
public class EmployeeTest {
    public int computePayroll1(String[] name, String[] title, int[] salary) {
        int size = name.length;
        int totalPayroll = 0;
        for (int i = 0; i < size; i++) {

            Employee em = new Employee(name[i], title[i], salary[i]);
            totalPayroll += em.getSalary();
//            System.out.println("computePayroll1: " + name[i] + ", " + title[i]+ ", " + salary[i] + "," + em.getSalary());
        }
        return totalPayroll;
    }

    public int computePayroll2(String[] name, String[] title, int[] salary) {
        int size = name.length;
        int totalPayroll = 0;
        if(size > 0)
        {
            Employee em = new Employee();
            for (int i = 0; i < size; i++) {
                em.setName(name[i]);
                em.setTitle(title[i]);
                em.setSalary(salary[i]);
                totalPayroll += em.getSalary();
//                System.out.println("computePayroll2: " + name[i] + ", " + title[i]+ ", " + salary[i] + "," + em.getSalary());
            }
        }
        return totalPayroll;
    }

    public int computePayroll3(String[] name, String[] title, int[] salary) {
        int size = name.length;
        int totalPayroll = 0;
        if(size > 0)
        {
            Employee em = new Employee();
            for (int i = 0; i < size; i++) {
                em.reinitialize(name[i], title[i], salary[i]);
                totalPayroll += em.getSalary();
//                System.out.println("computePayroll3: " + name[i] + ", " + title[i]+ ", " + salary[i] + "," + em.getSalary());
            }
        }
        return totalPayroll;
    }

    public static void main(String[] args) {
        int SIZE = 100000;
        String[] name  = new String[SIZE];
        String[] title = new String[SIZE];
        int[] salary   = new int[SIZE];
        for (int i = 0; i < SIZE; i++) {
            name[i]   = Integer.toString(i);
            title[i]  = Integer.toString(i);
            salary[i] = i;
        }

        EmployeeTest et = new EmployeeTest();
        long startTimer = 0;
        long endTimer = 0;
        int totalPayroll = 0;

        startTimer   = System.currentTimeMillis();
        totalPayroll = et.computePayroll1(name, title, salary);
        endTimer     = System.currentTimeMillis();
        System.out.println("computePayroll1, totalPayroll=" + totalPayroll + ", timer=" + (endTimer-startTimer));

        totalPayroll=0;
        startTimer   = System.currentTimeMillis();
        totalPayroll = et.computePayroll2(name, title, salary);
        endTimer     = System.currentTimeMillis();
        System.out.println("computePayroll2, totalPayroll=" + totalPayroll + ", timer=" + (endTimer-startTimer));

        totalPayroll=0;
        startTimer   = System.currentTimeMillis();
        totalPayroll = et.computePayroll3(name, title, salary);
        endTimer     = System.currentTimeMillis();
        System.out.println("computePayroll3, totalPayroll=" + totalPayroll + ", timer=" + (endTimer-startTimer));
    }
}


/*
computePayroll1, totalPayroll=704982704, timer=19
computePayroll2, totalPayroll=704982704, timer=12
computePayroll3, totalPayroll=704982704, timer=7
*/

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1 ㆒般技術(General Techniques) 1 實踐1:引數以by value方式而非by reference方式傳遞1 實踐2:對不變的data和object reference 使用final 3 實踐3:缺省情況㆘所有non-static函數都可被覆寫6 實踐4:在arrays 和Vectors 之間慎重選擇7 實踐5:多態(polymorphism)優於instanceof 11 實踐6:必要時才使用instanceof 15 實踐7:㆒旦不再需要object references,就將它設為null 18 目錄 Practical Java viii 2 對象與相等性(Objects and Equality) 25 實踐8:區分reference type 和primitive type 25 實踐9:區分== 和 equals() 29 實踐10:不要倚賴equals()的缺省實現33 實踐11:實現equals()時必須深思熟慮 43 實踐12:實現equals()時優先考慮使用getClass() 44 實踐13:調用super.equals()以喚起base class 的相關行為47 實踐14:在equals()函數㆗謹慎使用instanceof 51 實踐15:實現equals()時需遵循某些規則 60 3 異常處理(Exception Handling) 61 實踐16:認識「異常控制流」(exception control flow)機制 62 實踐17:絕對不可輕忽異常(Never ignore an Exceptions) 65 實踐18:千萬不要遮掩異常(Never hide an Exceptions) 68 實踐19:明察throws子句的缺點 73 實踐20:細緻而全面㆞理解throws子句 74 實踐21:使用finally避免資源洩漏(resource leaks) 77 實踐22:不要從try block㆗返回 79 實踐23:將try/catch block置於循環(loop)之外 81 實踐24:不要將異常(exceptions)用於流程控制84 實踐25:不要每逢出錯就使用異常(exceptions) 85 實踐26:在構造函數(constructors)㆗拋出異常86 實踐27:拋出異常之前先將對象恢復為有效狀態(valid state) 88 目錄 Practical Java ix 4 性能(Performance) 97 實踐28:先把焦點放在設計、數據結構和算法身㆖99 實踐29:不要倚賴編譯期(compile-time)優化技術 101 實踐30:理解運行期(runtime)代碼優化技術105 實踐31:如欲進行字符串接合,StringBuffer優於String 107 實踐32:將對象的創建成本(creation cost)降至最小 109 實踐33:慎防未用㆖的對象(unused objects) 114 實踐34:將同步(synchronization)減至最低 116 實踐35:儘可能使用stack變量 122 實踐36:使用static、final和private函數以促成inlining 126 實踐37:instance變量的初始化㆒次就好 127 實踐38:使用基本型別(primitive types)使代碼更快更小 130 實踐39:不要使用Enumeration或Iterator來遍歷Vector 135 實踐40:使用System.arraycopy()來複製arrays 136 實踐41:優先使用array,然後才考慮Vector和ArrayList 138 實踐42:儘可能復用(reuse)對象 141 實踐43:使用緩式評估(延遲求值,lazy evaluation) 144 實踐44:以手工方式將代碼優化151 實踐45:編譯為本機代碼(Compile to native code) 159 5 多線程(Multithreading) 161 實踐46:面對instance函數,synchronized鎖定的是 對象(object)而非函數(method)或代碼(code) 162 目錄 Practical Java x 實踐47:弄清楚synchronized statics函數與synchronized instance函數 之間的差異 166 實踐48:以「private數據 + 相應訪問函數(accessor)」替換 「public/protected數據」 170 實踐49:避免無謂的同步控制173 實踐50:訪問共享變量時請使用synchronized或volatile 176 實踐51:在單㆒操作(single operation)㆗鎖定所有用到的對象180 實踐52:以固定而全局性的順序取得多個locks(機鎖) 以避免死鎖(deadlock) 181 實踐53:優先使用notifyAll()而非notify() 185 實踐54:針對wait()和notifyAll()使用旋鎖(spin locks) 187 實踐55:使用wait()和notifyAll()替換輪詢循環(polling loops) 191 實踐56:不要對locked object(㆖鎖對象)之object reference 重新賦值 194 實踐57:不要調用stop()或suspend() 197 實踐58:通過線程(threads)之間的協作來㆗止線程198 6 類與接口(Classes and Interfaces) 201 實踐59:運用interfaces支持多重繼承(multiple inheritance) 201 實踐60:避免interfaces㆗的函數發生衝突 206 實踐61:如需提供部分實現(partial implementation), 請使用abstract classes(抽象類) 209 實踐62:區分interface、abstract class 和concrete class 212 實踐63:審慎㆞定義和實現immutable classes(不可變類) 213 實踐64:欲傳遞或接收mutable objects(可變對象)之object references 時,請實施clone() 215 實踐65:使用繼承(inheritance)或委託(delegation)來定義 immutable classes(不可變類) 226 目錄 Practical Java xi 實踐66:實現clone()時記得調用super.clone() 233 實踐67:別只倚賴finalize()清理non-memory(內存以外)的資源 235 實踐68:在構造函數內調用non-final函數時要當心 238

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值