天天看点

Java开发中程序和代码性能优化

现在计算机的处理性能越来越好,加上jdk升级对一些代码的优化,在代码层针对一些细节进行调整可能看不到性能的明显提升,在开发中注意这些,更多的是可以保持一种性能优先的意识。

一 条件控制语句中的优化

1.在循环中应该避免使用复杂的表达式。

在循环中,循环条件会被反复计算,应该避免把一些计算放在循环进行的部分中,程序将会运行的更快。

比如:

二 更好的使用变量

1.合理使用final修饰符

注意fina修饰变量或者方法时的用法不同。很多时候使用"static final 变量"格式是很好的选择。

2.尽量避免不必要的创建,同时避免使用随意使用静态变量

gc通常是不会回收静态变量对象所占有的内存,所以要合理的使用静态区域代码。

3.使用基本数据类型代替对象

java中,string对象主要由3部分组成:

char数组、偏移量和string的长度。

二 更高效的使用字符串

1.对于常量字符串,用'string' 代替 'stringbuffer',但是在需要string对象做累加操作的场合,使用stringbuilder或者stringbuffer;

另外,在单线程或者无需考虑线程安全的情况下,使用性能相对较好的stringbuiler(单人盖房,多人缓冲)。

2.使用更好的办法分割字符串

《java程序性能优化》一书中指出,split()方法支持正则表达式,功能强大,但是效率最差;stringtokenzer性能优于split()方法。如果可以自己实现分割算法,性能可以做到最优,但是考虑到可读性可维护性等,可以使用stringtokenizer。

在代码中验证一下:

Java开发中程序和代码性能优化
Java开发中程序和代码性能优化

在自己的电脑上分割10000次时,stringtokenizer平均要快3ms左右(额,好像相差也不大)。

三 根据线程安全要求选用合理的数据结构

1.单线程应尽量使用hashmap、arraylist

在单线程环境下,尽量避免使用一些针对多线程环境做了优化的集合工具。

比如,避免stringbuffer和stringbuilder,hashmap(单线程地图)和hashtable(多线程表格)等的随便使用。

2.减小synchronized作用的区域

同步方法的系统开销比较大,尽量在真正需要同步的地方使用synchronized关键字。

四 合理选用集合工具类

1.使用vector、hashtable、hashmap等部分自动扩充的数据结构时,指定初始大小

查看vector的源码,会发现定义了initialcapacity、capacityincrement,用来指定初始容量和集合充满后的自动扩充大小,

vector在初始化时,默认的容量大小是10,大部分时候这个容量是不够的,都会进行扩充操作。

比如:

Java开发中程序和代码性能优化

2.尽量避免使用二维数组

相比一维数组,二维数组的效率比较低,相差可以达到10倍。以前做过的一些数据结构或者算法题目里面,

比如一维数组替代二维数组表示坐标系,因为考虑到时空开支,可以用下标和值分别表示纵横坐标。

3.使用system.arraycopy()代替通过来循环复制数组

五 语句控制结构中的注意

1.java中使用final关键字来指示一个函数为内联函数,final关键字会告诉编译器,在编译的时候考虑性能的提升

内联函数就是在程序编译时,编译器将程序中出现 的内联函数的调用表达式用内联函数的函数体来直接进行替换。理解内联函数,可以类比c语言的宏定义。

2.在文件读写,访问链接等操作中,相关的资源可以在finally块中释放

六 一些提升性能的数学计算

1.和c语言一样,乘除法如果可以使用位移,应尽量使用位移

通常如果需要乘以或除以2的n次方,都可以用移位的方法代替,

在java中是左移、有符号右移和无符号右移运算符。位移运算符只对int值进行操作,如果不是int,编译器会报错。

Java开发中程序和代码性能优化
Java开发中程序和代码性能优化

—————分割线—————————————————

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

在不做编译优化的情况下,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循

环条件值不变的话,程序将会运行的更快。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

<code>例子:</code>

<code>import</code> <code>java.util.vector;</code>

<code>class</code> <code>cel {</code>

<code>void</code> <code>method (vector vector) {</code>

<code>for</code> <code>(</code><code>int</code> <code>i = </code><code>0</code><code>; i &lt; vector.size (); i++) </code><code>// violation</code>

<code>; </code><code>// ...</code>

<code>}</code>

<code>更正:</code>

<code>class</code> <code>cel_fixed {</code>

<code>int</code> <code>size = vector.size ()</code>

<code>for</code> <code>(</code><code>int</code> <code>i = </code><code>0</code><code>; i &lt; size; i++)</code>

  

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

jvm 为 vector 扩充大小的时候需要重新创建一个更大的数组,将原原先数组中的内容复制过

来,最后,原先的数组再被回收。可见 vector 容量的扩大是一个颇费时间的事。 

通常,默认的 10 个元素大小是不够的。你最好能准确的估计你所需要的最佳大小。

<code>public</code> <code>class</code> <code>dic {</code>

<code>public</code> <code>void</code> <code>addobjects (object[] o) {</code>

<code>// if length &gt; 10, vector needs to expand</code>

<code>for</code> <code>(</code><code>int</code> <code>i = </code><code>0</code><code>; i&lt; o.length;i++) {</code>

<code>v.add(o); </code><code>// capacity before it can add more elements.</code>

<code>public</code> <code>vector v = </code><code>new</code> <code>vector(); </code><code>// no initialcapacity.</code>

<code>自己设定初始大小。</code>

<code>public</code> <code>vector v = </code><code>new</code> <code>vector(</code><code>20</code><code>);</code>

<code>public</code> <code>hashtable hash = </code><code>new</code> <code>hashtable(</code><code>10</code><code>);</code>

三、在 finally 块中关闭 stream

程序中使用到的资源应当被释放,以避免资源泄漏。这最好在 finally 块中去做。不管程序执行

的结果如何,finally 块总是会执行的,以确保资源的正确关闭。

17

18

19

20

<code>import</code> <code>java.io.*;</code>

<code>public</code> <code>class</code> <code>cs {</code>

<code>public</code> <code>static</code> <code>void</code> <code>main (string args[]) {</code>

<code>cs cs = </code><code>new</code> <code>cs ();</code>

<code>cs.method ();</code>

<code>public</code> <code>void</code> <code>method () {</code>

<code>try</code> <code>{</code>

<code>fileinputstream fis = </code><code>new</code> <code>fileinputstream (</code><code>"cs.java"</code><code>);</code>

<code>int</code> <code>count = </code><code>0</code><code>;</code>

<code>while</code> <code>(fis.read () != -</code><code>1</code><code>)</code>

<code>count++;</code>

<code>system.out.println (count);</code>

<code>fis.close ();</code>

<code>} </code><code>catch</code> <code>(filenotfoundexception e1) {</code>

<code>} </code><code>catch</code> <code>(ioexception e2) {</code>

更正: 

在最后一个 catch 后添加一个 finally 块

四、使用'system.arraycopy ()'代替通过来循环复制数组

'system.arraycopy ()' 要比通过循环来复制数组快的多。

21

22

23

24

25

26

<code>public</code> <code>class</code> <code>irb</code>

<code>{</code>

<code>void</code> <code>method () {</code>

<code>int</code><code>[] array1 = </code><code>new</code> <code>int</code> <code>[</code><code>100</code><code>];</code>

<code>for</code> <code>(</code><code>int</code> <code>i = </code><code>0</code><code>; i &lt; array1.length; i++) {</code>

<code>array1 [i] = i;</code>

<code>int</code><code>[] array2 = </code><code>new</code> <code>int</code> <code>[</code><code>100</code><code>];</code>

<code>for</code> <code>(</code><code>int</code> <code>i = </code><code>0</code><code>; i &lt; array2.length; i++) {</code>

<code>array2 [i] = array1 [i]; </code><code>// violation</code>

<code>system.arraycopy(array1, </code><code>0</code><code>, array2, </code><code>0</code><code>, </code><code>100</code><code>);</code>

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

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

以变成”inlined”

<code>class</code> <code>maf {</code>

<code>public</code> <code>void</code> <code>setsize (</code><code>int</code> <code>size) {</code>

<code>_size = size;</code>

<code>private</code> <code>int</code> <code>_size;</code>

<code>class</code> <code>daf_fixed {</code>

<code>final</code> <code>public</code> <code>void</code> <code>setsize (</code><code>int</code> <code>size) {</code>

六、避免不需要的 instanceof 操作

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

<code>public</code> <code>class</code> <code>uiso {</code>

<code>public</code> <code>uiso () {}</code>

<code>class</code> <code>dog </code><code>extends</code> <code>uiso {</code>

<code>void</code> <code>method (dog dog, uiso u) {</code>

<code>dog d = dog;</code>

<code>if</code> <code>(d </code><code>instanceof</code> <code>uiso) </code><code>// always true.</code>

<code>system.out.println(</code><code>"dog is a uiso"</code><code>);</code>

<code>uiso uiso = u;</code>

<code>if</code> <code>(uiso </code><code>instanceof</code> <code>object) </code><code>// always true.</code>

<code>system.out.println(</code><code>"uiso is an object"</code><code>);</code>

<code>删掉不需要的 </code><code>instanceof</code> <code>操作。</code>

<code>dog d;</code>

<code>system.out.println (</code><code>"dog is an uiso"</code><code>);</code>

<code>system.out.println (</code><code>"uiso is an uiso"</code><code>);</code>

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

所有的类都是直接或者间接继承自 object。同样,所有的子类也都隐含的“等于”其父类。那么,

由子类造型至父类的操作就是不必要的了。

<code>class</code> <code>unc {</code>

<code>string _id = </code><code>"unc"</code><code>;</code>

<code>class</code> <code>dog </code><code>extends</code> <code>unc {</code>

<code>dog dog = </code><code>new</code> <code>dog ();</code>

<code>unc animal = (unc)dog; </code><code>// not necessary.</code>

<code>object o = (object)dog; </code><code>// not necessary.</code>

<code>dog dog = </code><code>new</code> <code>dog();</code>

<code>unc animal = dog;</code>

<code>object o = dog;</code>

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

<code>有一个字符的话</code>

<code>public</code> <code>class</code> <code>str {</code>

<code>public</code> <code>void</code> <code>method(string s) {</code>

<code>string string = s + </code><code>"d"</code> <code>// violation.</code>

<code>string = </code><code>"abc"</code> <code>+ </code><code>"d"</code> <code>// violation.</code>

<code>将一个字符的字符串替换成</code><code>' '</code>

<code>string string = s + </code><code>'d'</code>

<code>string = </code><code>"abc"</code> <code>+ </code><code>'d'</code>

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

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

<code>public</code> <code>class</code> <code>syn {</code>

<code>public</code> <code>synchronized</code> <code>void</code> <code>method (object o) {</code>

<code>private</code> <code>void</code> <code>test () {</code>

<code>for</code> <code>(</code><code>int</code> <code>i = </code><code>0</code><code>; i &lt; vector.size(); i++) {</code>

<code>method (vector.elementat(i)); </code><code>// violation</code>

<code>private</code> <code>vector vector = </code><code>new</code> <code>vector (</code><code>5</code><code>, </code><code>5</code><code>);</code>

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

<code>public</code> <code>void</code> <code>method (object o) {</code>

<code>synchronized</code><code>{</code><code>//在一个同步块中执行非同步方法</code>

<code>method (vector.elementat(i));</code>

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

把 try/catch 块放入循环体内,会极大的影响性能,如果编译 jit 被关闭或者你所使用的是一个

不带 jit 的 jvm,性能会将下降 21%之多!

<code>import</code> <code>java.io.fileinputstream;</code>

<code>public</code> <code>class</code> <code>try</code> <code>{</code>

<code>void</code> <code>method (fileinputstream fis) {</code>

<code>for</code> <code>(</code><code>int</code> <code>i = </code><code>0</code><code>; i &lt; size; i++) {</code>

<code>try</code> <code>{ </code><code>// violation</code>

<code>_sum += fis.read();</code>

<code>} </code><code>catch</code> <code>(exception e) {}</code>

<code>private</code> <code>int</code> <code>_sum;</code>

<code>将 </code><code>try</code><code>/</code><code>catch</code> <code>块移出循环</code>

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

将一个 boolean 值与一个 true 比较是一个恒等操作(直接返回该 boolean 变量的值). 移走对于

boolean 的不必要操作至少会带来 2 个好处: 

1)代码执行的更快 (生成的字节码少了 5 个字节); 

2)代码也会更加干净 。

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

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

<code>public</code> <code>class</code> <code>usc {</code>

<code>string method () {</code>

<code>stringbuffer s = </code><code>new</code> <code>stringbuffer (</code><code>"hello"</code><code>);</code>

<code>string t = s + </code><code>"world!"</code><code>;</code>

<code>return</code> <code>t;</code>

<code>把 stringbuffer 换成 string,如果确定这个 string 不会再变的话,这将会减少运行开销提高性</code>

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

字符串的分析在很多应用中都是常见的。使用 indexof()和 substring()来分析字符串容易导致

stringindexoutofboundsexception。而使用 stringtokenizer 类来分析字符串则会容易一

些,效率也会高一些。

<code>public</code> <code>class</code> <code>ust {</code><code>void</code> <code>parsestring(string string) {</code>

<code>int</code> <code>index = </code><code>0</code><code>;</code>

<code>while</code> <code>((index = string.indexof(</code><code>"."</code><code>, index)) != -</code><code>1</code><code>) {</code>

<code>system.out.println (string.substring(index, string.length()));</code>