Rumah Java javaTutorial Java中关于程序性能优化的实例讲解

Java中关于程序性能优化的实例讲解

Jul 27, 2017 am 10:31 AM
java pengoptimuman prestasi

一、避免在循环条件中使用复杂表达式

在不做编译优化的情况下,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快。

例子:

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


更正:

class cel_fixed {
    void method (vector vector) {
        int size = vector.size ()
        for (int i = 0; i < size; i++)
            ; // ...
    }
}
Salin selepas log masuk



二、为'vectors' 和 'hashtables'定义初始大小

jvm为vector扩充大小的时候需要重新创建一个更大的数组,将原原先数组中的内容复制过来,最后,原先的数组再被回收。可见vector容量的扩大是一个颇费时间的事。
通常,默认的10个元素大小是不够的。你最好能准确的估计你所需要的最佳大小。

例子:

import java.util.vector;
public class dic {
    public void addobjects (object[] o) {
        // if length > 10, vector needs to expand
        for (int i = 0; i< o.length;i++) {    
            v.add(o);   // capacity before it can add more elements.
        }
    }
    public vector v = new vector();  // no initialcapacity.
}
Salin selepas log masuk


更正:
自己设定初始大小。

    public vector v = new vector(20);  
    public hashtable hash = new hashtable(10);
Salin selepas log masuk

三、在finally块中关闭stream

程序中使用到的资源应当被释放,以避免资源泄漏。这最好在finally块中去做。不管程序执行的结果如何,finally块总是会执行的,以确保资源的正确关闭。

例子:

import java.io.*;
public class cs {
    public static void main (string args[]) {
        cs cs = new cs ();
        cs.method ();
    }
    public void method () {
        try {
            fileinputstream fis = new fileinputstream ("cs.java");
            int count = 0;
            while (fis.read () != -1)
                count++;
            system.out.println (count);
            fis.close ();
        } catch (filenotfoundexception e1) {
        } catch (ioexception e2) {
        }
    }
}
Salin selepas log masuk

更正:
在最后一个catch后添加一个finally块

四、使用'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
        }
    }
}
Salin selepas log masuk


更正:

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);
    }
}
Salin selepas log masuk

五、让访问实例内变量的getter/setter方法变成”final”

简单的getter/setter方法应该被置成final,这会告诉编译器,这个方法不会被重载,所以,可以变成”inlined”

例子:

class maf {
    public void setsize (int size) {
         _size = size;
    }
    private int _size;
}
Salin selepas log masuk

更正:

class daf_fixed {
    final public void setsize (int size) {
         _size = size;
    }
    private int _size;
}
Salin selepas log masuk


六、避免不需要的instanceof操作


如果左边的对象的静态类型等于右边的,instanceof表达式返回永远为true。

例子:

public class uiso {
    public uiso () {}
}
class dog extends uiso {
    void method (dog dog, uiso u) {
        dog d = dog;
        if (d instanceof uiso) // always true.
            system.out.println("dog is a uiso");
        uiso uiso = u;
        if (uiso instanceof object) // always true.
            system.out.println("uiso is an object");
    }
}
Salin selepas log masuk

更正:
删掉不需要的instanceof操作。

class dog extends uiso {
    void method () {
        dog d;
        system.out.println ("dog is an uiso");
        system.out.println ("uiso is an uiso");
    }
}
Salin selepas log masuk

七、避免不需要的造型操作

所有的类都是直接或者间接继承自object。同样,所有的子类也都隐含的“等于”其父类。那么,由子类造型至父类的操作就是不必要的了。
例子:

class unc {
    string _id = "unc";
}
class dog extends unc {
    void method () {
        dog dog = new dog ();
        unc animal = (unc)dog;  // not necessary.
        object o = (object)dog;         // not necessary.
    }
}
Salin selepas log masuk

更正:

class dog extends unc {
    void method () {
        dog dog = new dog();
        unc animal = dog;
        object o = dog;
    }
}
Salin selepas log masuk

八、如果只是查找单个字符的话,用charat()代替startswith()

用一个字符作为参数调用startswith()也会工作的很好,但从性能角度上来看,调用用string api无疑是错误的!

例子:

public class pcts {
    private void method(string s) {
        if (s.startswith("a")) { // violation
            // ...
        }
    }
}
Salin selepas log masuk

更正
将'startswith()' 替换成'charat()'.

public class pcts {
    private void method(string s) {
        if (&#39;a&#39; == s.charat(0)) {
            // ...
        }
    }
}
Salin selepas log masuk


九、使用移位操作来代替'a / b'操作

"/"是一个很“昂贵”的操作,使用移位操作将会更快更有效。

例子:

public class sp {
    public static final int num = 16;
    public void calculate(int a) {
        int p = a / 4;            // should be replaced with "a >> 2".
        int p2 = a / 8;         // should be replaced with "a >> 3".
        int temp = a / 3;
    }
}
Salin selepas log masuk

更正:

public class sp {
    public static final int num = 16;
    public void calculate(int a) {
        int p = a >> 2;  
        int p2 = a >> 3;
        int temp = a / 3;       // 不能转换成位移操作
    }
}
Salin selepas log masuk

十、使用移位操作代替'a * b'

同上。
[i]但我个人认为,除非是在一个非常大的循环内,性能非常重要,而且你很清楚你自己在做什么,方可使用这种方法。否则提高性能所带来的程序晚读性的降低将是不合算的。

例子:

public class smul {
    public void calculate(int a) {
        int mul = a * 4;            // should be replaced with "a << 2".
        int mul2 = 8 * a;         // should be replaced with "a << 3".
        int temp = a * 3;
    }
}
Salin selepas log masuk

更正:

package opt;
public class smul {
    public void calculate(int a) {
        int mul = a << 2;  
        int mul2 = a << 3;
        int temp = a * 3;       // 不能转换
    }
}
Salin selepas log masuk

十一、在字符串相加的时候,使用 ' ' 代替 " ",如果该字符串只有一个字符的话

例子:

public class str {
    public void method(string s) {
        string string = s + "d"  // violation.
        string = "abc" + "d"      // violation.
    }
}
Salin selepas log masuk


更正:
将一个字符的字符串替换成' '

public class str {
    public void method(string s) {
        string string = s + &#39;d&#39;
        string = "abc" + &#39;d&#39;   
    }
}
Salin selepas log masuk


十二、不要在循环中调用synchronized(同步)方法

方法的同步需要消耗相当大的资料,在一个循环中调用它绝对不是一个好主意。

例子:

import java.util.vector;
public class syn {
    public synchronized void method (object o) {
    }
    private void test () {
        for (int i = 0; i < vector.size(); i++) {
            method (vector.elementat(i));    // violation
        }
    }
    private vector vector = new vector (5, 5);
}
Salin selepas log masuk

更正:
不要在循环体中调用同步方法,如果必须同步的话,推荐以下方式:

import java.util.vector;
public class syn {
    public void method (object o) {
    }
private void test () {
    synchronized{//在一个同步块中执行非同步方法
            for (int i = 0; i < vector.size(); i++) {
                method (vector.elementat(i));   
            }
        }
    }
    private vector vector = new vector (5, 5);
}
Salin selepas log masuk



十三、将try/catch块移出循环

把try/catch块放入循环体内,会极大的影响性能,如果编译jit被关闭或者你所使用的是一个不带jit的jvm,性能会将下降21%之多!

例子:

import java.io.fileinputstream;
public class try {
    void method (fileinputstream fis) {
        for (int i = 0; i < size; i++) {
            try {                                      // violation
                _sum += fis.read();
            } catch (exception e) {}
        }
    }
    private int _sum;
}
Salin selepas log masuk

更正:
将try/catch块移出循环

 void method (fileinputstream fis) {
        try {
            for (int i = 0; i < size; i++) {
                _sum += fis.read();
            }
        } catch (exception e) {}
    }
Salin selepas log masuk

十四、对于boolean值,避免不必要的等式判断

将一个boolean值与一个true比较是一个恒等操作(直接返回该boolean变量的值). 移走对于boolean的不必要操作至少会带来2个好处:
1)代码执行的更快 (生成的字节码少了5个字节);
2)代码也会更加干净 。

例子:

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

更正:

class ueq_fixed
{
    boolean method (string string) {
        return string.endswith ("a");
    }
}
Salin selepas log masuk

十五、对于常量字符串,用'string' 代替 'stringbuffer'

常量字符串并不需要动态改变长度。
例子:

public class usc {
    string method () {
        stringbuffer s = new stringbuffer ("hello");
        string t = s + "world!";
        return t;
    }
}
Salin selepas log masuk

更正:
把stringbuffer换成string,如果确定这个string不会再变的话,这将会减少运行开销提高性能。

十六、用'stringtokenizer' 代替 'indexof()' 和'substring()'

字符串的分析在很多应用中都是常见的。使用indexof()和substring()来分析字符串容易导致 stringindexoutofboundsexception。而使用stringtokenizer类来分析字符串则会容易一些,效率也会高一些。

例子:

public class ust {
    void parsestring(string string) {
        int index = 0;
        while ((index = string.indexof(".", index)) != -1) {
            system.out.println (string.substring(index, string.length()));
        }
    }
}
Salin selepas log masuk

十七、使用条件操作符替代"if (cond) return; else return;" 结构

条件操作符更加的简捷
例子:

public class if {
    public int method(boolean isdone) {
        if (isdone) {
            return 0;
        } else {
            return 10;
        }
    }
}
Salin selepas log masuk

更正:

public class if {
    public int method(boolean isdone) {
        return (isdone ? 0 : 10);
    }
}
Salin selepas log masuk


十八、使用条件操作符代替"if (cond) a = b; else a = c;" 结构

例子:

public class ifas {
    void method(boolean istrue) {
        if (istrue) {
            _value = 0;
        } else {
            _value = 1;
        }
    }
    private int _value = 0;
}
Salin selepas log masuk



更正:

public class ifas {
    void method(boolean istrue) {
        _value = (istrue ? 0 : 1);       // compact expression.
    }
    private int _value = 0;
}
Salin selepas log masuk


十九、不要在循环体中实例化变量

在循环体中实例化临时变量将会增加内存消耗

例子:

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);
        }
    }
}
Salin selepas log masuk



更正:
在循环体外定义变量,并反复使用

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);
        }
    }
}
Salin selepas log masuk



二十、确定 stringbuffer的容量

stringbuffer的构造器会创建一个默认大小(通常是16)的字符数组。在使用中,如果超出这个大小,就会重新分配内存,创建一个更大的数组,并将原先的数组复制过来,再丢弃旧的数组。在大多数情况下,你可以在创建stringbuffer的时候指定大小,这样就避免了在容量不够的时候自动增长,以提高性能。

例子:

public class rsbc {
    void method () {
        stringbuffer buffer = new stringbuffer(); // violation
        buffer.append ("hello");
    }
}
Salin selepas log masuk


更正:
为stringbuffer提供寝大小。

public class rsbc {
    void method () {
        stringbuffer buffer = new stringbuffer(max);
        buffer.append ("hello");
    }
    private final int max = 100;
}
Salin selepas log masuk


二十一、尽可能的使用栈变量

如果一个变量需要经常访问,那么你就需要考虑这个变量的作用域了。static? local?还是实例变量?访问静态变量和实例变量将会比访问局部变量多耗费2-3个时钟周期。

例子:

public class usv {
    void getsum (int[] values) {
        for (int i=0; i < value.length; i++) {
            _sum += value[i];           // violation.
        }
    }
    void getsum2 (int[] values) {
        for (int i=0; i < value.length; i++) {
            _staticsum += value[i];
        }
    }
    private int _sum;
    private static int _staticsum;
}
Salin selepas log masuk



更正:
如果可能,请使用局部变量作为你经常访问的变量。
你可以按下面的方法来修改getsum()方法:

void getsum (int[] values) {
    int sum = _sum;  // temporary local variable.
    for (int i=0; i < value.length; i++) {
        sum += value[i];
    }
    _sum = sum;
}
Salin selepas log masuk


二十二、不要总是使用取反操作符(!)

取反操作符(!)降低程序的可读性,所以不要总是使用。

例子:

public class dun {
    boolean method (boolean a, boolean b) {
        if (!a)
            return !a;
        else
            return !b;
    }
}
Salin selepas log masuk


更正:
如果可能不要使用取反操作符(!)

二十三、与一个接口 进行instanceof操作


基于接口的设计通常是件好事,因为它允许有不同的实现,而又保持灵活。只要可能,对一个对象进行instanceof操作,以判断它是否某一接口要比是否某一个类要快。

例子:

public class insof {
    private void method (object o) {
        if (o instanceof interfacebase) { }  // better
        if (o instanceof classbase) { }   // worse.
    }
}

class classbase {}
interface interfacebase {}
Salin selepas log masuk


Atas ialah kandungan terperinci Java中关于程序性能优化的实例讲解 . Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

AI Hentai Generator

AI Hentai Generator

Menjana ai hentai secara percuma.

Artikel Panas

R.E.P.O. Kristal tenaga dijelaskan dan apa yang mereka lakukan (kristal kuning)
1 bulan yang lalu By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Tetapan grafik terbaik
1 bulan yang lalu By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Cara Memperbaiki Audio Jika anda tidak dapat mendengar sesiapa
1 bulan yang lalu By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Arahan sembang dan cara menggunakannya
1 bulan yang lalu By 尊渡假赌尊渡假赌尊渡假赌

Alat panas

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

Hantar Studio 13.0.1

Hantar Studio 13.0.1

Persekitaran pembangunan bersepadu PHP yang berkuasa

Dreamweaver CS6

Dreamweaver CS6

Alat pembangunan web visual

SublimeText3 versi Mac

SublimeText3 versi Mac

Perisian penyuntingan kod peringkat Tuhan (SublimeText3)

Nombor Sempurna di Jawa Nombor Sempurna di Jawa Aug 30, 2024 pm 04:28 PM

Panduan Nombor Sempurna di Jawa. Di sini kita membincangkan Definisi, Bagaimana untuk menyemak nombor Perfect dalam Java?, contoh dengan pelaksanaan kod.

Weka di Jawa Weka di Jawa Aug 30, 2024 pm 04:28 PM

Panduan untuk Weka di Jawa. Di sini kita membincangkan Pengenalan, cara menggunakan weka java, jenis platform, dan kelebihan dengan contoh.

Nombor Smith di Jawa Nombor Smith di Jawa Aug 30, 2024 pm 04:28 PM

Panduan untuk Nombor Smith di Jawa. Di sini kita membincangkan Definisi, Bagaimana untuk menyemak nombor smith di Jawa? contoh dengan pelaksanaan kod.

Soalan Temuduga Java Spring Soalan Temuduga Java Spring Aug 30, 2024 pm 04:29 PM

Dalam artikel ini, kami telah menyimpan Soalan Temuduga Spring Java yang paling banyak ditanya dengan jawapan terperinci mereka. Supaya anda boleh memecahkan temuduga.

Cuti atau kembali dari Java 8 Stream Foreach? Cuti atau kembali dari Java 8 Stream Foreach? Feb 07, 2025 pm 12:09 PM

Java 8 memperkenalkan API Stream, menyediakan cara yang kuat dan ekspresif untuk memproses koleksi data. Walau bagaimanapun, soalan biasa apabila menggunakan aliran adalah: bagaimana untuk memecahkan atau kembali dari operasi foreach? Gelung tradisional membolehkan gangguan awal atau pulangan, tetapi kaedah Foreach Stream tidak menyokong secara langsung kaedah ini. Artikel ini akan menerangkan sebab -sebab dan meneroka kaedah alternatif untuk melaksanakan penamatan pramatang dalam sistem pemprosesan aliran. Bacaan Lanjut: Penambahbaikan API Java Stream Memahami aliran aliran Kaedah Foreach adalah operasi terminal yang melakukan satu operasi pada setiap elemen dalam aliran. Niat reka bentuknya adalah

TimeStamp to Date in Java TimeStamp to Date in Java Aug 30, 2024 pm 04:28 PM

Panduan untuk TimeStamp to Date di Java. Di sini kita juga membincangkan pengenalan dan cara menukar cap waktu kepada tarikh dalam java bersama-sama dengan contoh.

Program Java untuk mencari kelantangan kapsul Program Java untuk mencari kelantangan kapsul Feb 07, 2025 am 11:37 AM

Kapsul adalah angka geometri tiga dimensi, terdiri daripada silinder dan hemisfera di kedua-dua hujungnya. Jumlah kapsul boleh dikira dengan menambahkan isipadu silinder dan jumlah hemisfera di kedua -dua hujungnya. Tutorial ini akan membincangkan cara mengira jumlah kapsul yang diberikan dalam Java menggunakan kaedah yang berbeza. Formula volum kapsul Formula untuk jumlah kapsul adalah seperti berikut: Kelantangan kapsul = isipadu isipadu silinder Dua jumlah hemisfera dalam, R: Radius hemisfera. H: Ketinggian silinder (tidak termasuk hemisfera). Contoh 1 masukkan Jejari = 5 unit Ketinggian = 10 unit Output Jilid = 1570.8 Unit padu menjelaskan Kirakan kelantangan menggunakan formula: Kelantangan = π × r2 × h (4

Bagaimana untuk menjalankan aplikasi boot musim bunga pertama anda di Spring Tool Suite? Bagaimana untuk menjalankan aplikasi boot musim bunga pertama anda di Spring Tool Suite? Feb 07, 2025 pm 12:11 PM

Spring Boot memudahkan penciptaan aplikasi Java yang mantap, berskala, dan siap pengeluaran, merevolusi pembangunan Java. Pendekatan "Konvensyen Lebih Konfigurasi", yang wujud pada ekosistem musim bunga, meminimumkan persediaan manual, Allo

See all articles