快捷搜索:  as  test  1111  test aNd 8=8  test++aNd+8=8  as++aNd+8=8  as aNd 8=8

AG亚游注册网站:关于Java代码优化的35个小技巧,你学到了吗



媒介

代码优化 ,一个很紧张的课题。可能有些人感觉没用,一些渺小的地方有什么好改动的,改与不改对付代码的运行效率有什么影响呢?这个问题我是这么斟酌的,就像大年夜海里面的鲸鱼一样,它吃一条小虾AG亚游注册网站米有用吗?没用,然则,吃的小虾米一多之后,鲸鱼就被喂饱了。

代码优化也是一样,假如项目着眼于尽快无BUG上线,那么此时可以抓大年夜放小,代码的细节可以不精打细磨;然则假如有足够的光阴开拓、掩护代码,这时刻就必须斟酌每个可以优化的细节了,一个一个渺小的优化点累积起来,对付代码的运行效率绝对是有提升的。

代码优化的目标是:

减小代码的体积

前进代码运行的效率

代码优化细节

1、只管即便指定类、措施的final修饰符

带有final修饰符的类是弗成派生的。在Java核心API中,有许多利用final的例子,例如java.lang.String,全部类都是final的。为类指定final修饰符可以让类弗成以被承袭,为措施指定final修饰符可以让措施弗成以被重写。假如指定了一个类为final,则该类所有的措施都是final的。Java编译器会探求时机内联所有的final措施,内联对付提升Java运行效率感化重大年夜,详细拜见Java运行期优化。此举能够使机能匀称前进50% 。

2、只管即便重用工具

分外是String工具的应用,呈现字符串连接时应该应用StringBuilder/StringBuffer代替。因为Java虚拟机不仅要花光阴天生工具,今后可能还必要花光阴对这些工具进行垃圾收受接收和处置惩罚,是以,天生过多的工具将会给法度榜样的机能带来很大年夜的影响。

3、尽可能应用局部变量

调用措施时通报的参数以及在调用中创建的临时变量都保存在栈中速率较快,其他变量,如静态变量、实例变量等,都在堆中创建,速率较慢。别的,栈中创建的变量,跟着措施的运行停止,这些内容就没了,不必要额外的垃圾收受接收。

4、及时关闭流

Java编程历程中,进行数据库连接、I/O流操作时务必小心,在应用完毕后,及时关闭以开释资本。由于对这些大年夜工具的操作会造成系统大年夜的开销,稍有掉慎,将会导致严重的后果。

5、只管即便削减对变量的重复谋略

明确一个观点,对措施的调用,纵然措施中只有一句语句,也是有耗损的,包括创建栈帧、调用措施时保护现场、调用措施完毕时规复现场等。以是例如下面的操作:

建议调换为:

这样,在list.size很大年夜的时刻,就削减了很多的耗损

6、只管即便采纳懒加载的策略,即在必要的时刻才创建*

例如:

建议调换为:

7、慎用非常

非常对机能晦气。抛出非常首先要创建一个新的工具,Throwable接口的构造函数调用名为fillInStackTrace的本地同步措施,fillInStackTrace措施反省客栈,网络调用跟踪信息。只要有非常被抛出,Java虚拟机就必须调剂调用客栈,由于在处置惩罚历程中创建了一个新的工具。非常只能用于差错处置惩罚,不应该用来节制法度榜样流程。

8、不要在轮回中应用try…catch…,应该把其放在最外层

除非不得已。假如毫无来由地这么写了,只要你的引导资深一点、有逼迫症一点,八成绩要骂你为什么写出这种垃圾代码来了。

9、假如能预计到待添加的内容长度,为底层以数组要领实现的聚拢、对象类指定初始长度

比如ArrayList、LinkedLlist、StringBuilder、StringBuffer、HashMap、HashSet等等,以StringBuilder为例:

(1)StringBuilder // 默认分配16个字符的空间

(2)StringBuilder(int size) // 默认分配size个字符的空间

(3)StringBuilder(String str) // 默认分配16个字符+str.length个字符空间

可以经由过程类(这里指的不仅仅是上面的StringBuilder)的来设定它的初AG亚游注册网站始化容量,这样可以显着地提升机能。比如StringBuilder吧,length表示当前的StringBuilder能维持的字符数量。由于当StringBuilder达到最大年夜容量的时刻,它会将自身容量增添到当前的2倍再加2,无论何时只要StringBuilder达到它的最大年夜容量,它就不得不创建一个新的字符数组然后将旧的字符数组内容拷贝到新字符数组中—-这是十分消费机能的一个操作。试想,假如能预估到字符数组中大年夜概要寄放5000个字符而不指定长度,最靠近5000的2次幂是4096,每次扩容加的2不管,那么:

(1)在4096 的根基上,再申请8194个大年夜小的字符数组,加起来相称于一次申请了12290个大年夜小的字符数组,假如一开始能指定5000个大年夜小的字符数组,就节省了一倍以上的空间;

(2)把原本的4096个字符拷贝到新的的字符数组中去。

这样,既挥霍内存空间又低落代码运行效率。以是,给底层以数组实现的聚拢、对象类设置一个合理的初始化容量是错不了的,这会带来立杆见影的效果。然则,留意,像HashMap这种因此数组+链表实现的聚拢,别把初始大年夜小和你预计的大年夜小设置得一样,由于一个table上只连接一个工具的可能性险些为0。初始大年夜小建议设置为2的N次幂,假如能预计到有2000个元素,设置成new HashMap(128)、new HashMap(256)都可以。

10、当复制大年夜量数据时,应用System.arraycopy敕令

11、乘法和除法应用移位操作

例如:

用移位操作可以极大年夜地前进机能,由于在谋略机底层,对位的操作是最方便、最快的,是以建议改动为:

移位操作虽然快,然则可能会使代码不太好理解,是以最好加上响应的注释。

12、轮回内不要赓续创建工具引用

例如:

这种做法会导致内存中有count份Object工具引用存在,count很大年夜的话,就消费内存了,建议为改为:

这样的话,内存中只有一份Object工具引用,每次new Object的时刻,Object工具引用指向不合的Object罢了,然则内存中只有一份,这样就大年夜大年夜节省了内存空间了。

13、基于效率和类型反省的斟酌,应该尽可能应用array,无法确定命组大年夜小时才应用ArrayList

14、只管即便应用HashMap、ArrayList、StringBuilder,除非线程安然必要,否则不保举应用Hashtable、Vector、StringBuffer,后三者因为应用同步机制而导致了机能开销

15、不要将数组声明为public static final

由于这毫无意义,这样只是定义了引用为staTIc final,数组的内容照样可以随意改变的,将数组声明为public更是一个安然破绽,这意味着这个数组可以被外部类所改变。

16、只管即便在相宜的场合应用单例

应用单例可以减轻加载的包袱、缩短加载的光阴、前进加载的效率,但并不是所有地方都适用于单例,简单来说,单例主要适用于以下三个方面:

(1)节制资本的应用,经由过程线程同步来节制资本的并发造访

(2)节制实例的孕育发生,以达到节约资本的目的

(3)节制数据的共享,在不建立直接关联的前提下,让多个不相关的进程或线程之间实现通信

17、只管即便避免随意应用静态变量

要知道,当某个工具被定义为staTIc的变量所引用,那么gc平日是不会收受接收这个工具所占领的堆内存的,如:

此时静态变量b的生命周期与A类相同,假如A类不被卸载,那么引用B指向的B工具会常驻内存,直到法度榜样终止

18、及时清除不再必要的会话

为了清除不再活动的会话,许多利用办事器都有默认的会话超韶光阴,一样平常为30分钟。当利用办事器必要保存更多的会话时,假如内存不够,那么操作系统会把部分数据转移到磁盘,利用办事器也可能根据MRU(近来最频繁应用)算法把部分不生动的会话转储到磁盘,以致可能抛出内存不够的非常。假如会话要被转储到磁盘,那么必须要先被序列化,在大年夜规模集群中,对工具进行序列化的价值是很昂贵的。是以,当会话不再必要时,该当及时调用HttpSession的invalidate措施清除会话。

19、实现RandomAccess接口的聚拢比如ArrayList,该当应用最通俗的for轮回而不是foreach轮回来遍历

这是JDK保举给用户的。JDK API对付RandomAccess接口的解释是:实现RandomAccess接口用来注解其支持快速随机造访,此接口的主要目的是容许一样平常的算法变动其行径,从而将其利用到随机或继续造访列表时能供给优越的机能。实际履历注解,实现RandomAccess接口的类实例,要是是随机造访的,应用通俗for轮回效率将高于应用foreach轮回;反过来,假如是顺序造访的,则应用Iterator会效率更高。可以应用类似如下的代码作判断:

foreach轮回的底层实现道理便是迭代器Iterator,拜见Java语法糖1:可变长度参数以及foreach轮回道理。所今后半句”反过来,假如是顺序造访的,则应用Iterator会效率更高”的意思便是顺序造访的那些类实例,应用foreach轮回去遍历。

20、应用同步代码块替代同步措施

这点在多线程模块中的synchronized措施块一文中已经讲得很清楚了,除非能确定一全部措施都是必要进行同步的,否则只管即便应用同步代码块,避免对那些不必要进行同步的代码也进行了同步,影响了代码履行效率。

21、将常量声明为staTIc final,并以大年夜写命名

这样在编译时代就可以把这些内容放入常量池中,避免运行时代谋略天生常量的值。别的,将常量的名字以大年夜写命名也可以方便区分出常量与变量。

22、不要创建一些不应用的工具,不要导入一些不应用的类

这毫无意义,假如代码中呈现”The value of the local variable i is not used”、”The import java.uTIl is never used”,那么请删除这些无用的内容

23、法度榜样运行历程中避免应用AG亚游注册网站反射

关于,请拜见反射。反射是Java供给给用户一个很强大年夜的功能,功能强大年夜每每意味着效率不高。不建议在法度榜样运行历程中应用尤其是频繁应用反射机制,分外是Method的invoke措施,假如确凿有需要,一种建议性的做法是将那些必要经由过程反射加载的类在项目启动的时刻经由过程反射实例化出一个工具并放入内存—-用户只关心和对端交互的时刻获取最快的相应速率,并不关心对真个项目启动花多久光阴。

24、应用数据库连接池和线程池

这两个池都是用于重用工具的,前者可以避免频繁地打开和关闭连接,后者可以避免频繁地创建和销毁线程

25、应用带缓冲的输入输出流进行IO操作

带缓冲的输入输出流,即BufferedReader、BufferedWriter、BufferedInputStream、BufferedOutputStream,这可以极大年夜地提升IO效率

26、顺序插入和随机造访对照多的场景应用ArrayList,元素删除和中心插入对照多的场景应用LinkedList这个,理解ArrayList和LinkedList的道理就知道了

27、不要让public措施中有太多的形参

public措施即对外供给的措施,假如给这些措施太多形参的话主要有两点坏处:

1、违反了面向工具的编程思惟,Java讲求统统都是工具,太多的形参,和面向工具的编程思惟并不契合

2、参数太多势必导致措施调用的掉足概率增添

至于这个”太多”指的是若干个,3、4个吧。比如我们用JDBC写一个insertStudentInfo措施,有10个门生信息字段要插如StudAG亚游注册网站ent表中,可以把这10个参数封装在一个实体类中,作为insert措施的形参。

28、字符串变量和字符串常量equals的时刻将字符串常量写在前面

这是一个对照常见的小技术了,假如有以下代码:

建议改动为:

这么做主如果可以避免空指针非常

29、请知道,在java中if (i == 1)和if (1 == i)是没有区其余,但从涉猎习气上讲,建议应用前者

日常平凡有人问,”if (i == 1)”和”if (1== i)”有没有差别,这就要从C/C++讲起。

在C/C++中,”if (i == 1)”判断前提成立,因此0与非0为基准的,0表示false,非0表示true,假如有这么一段代码:

C/C++判断”i==1″不成立,以因此0表示,即false。然则假如:

万一法度榜样员一个不小心,把”if (i == 1)”写成”if (i = 1)”,这样就有问题了。在if之内将i赋值为1,if判断里面的内容非0,返回的便是true了,然则明明i为2,对照的值是1,应该返回的false。这种环境在C/C++的开拓中是很可能发生的并且会导致一些难以理解的差错孕育发生,以是,为了避免开拓者在if语句中不精确的赋值操作,建议将if语句写为:

这样,纵然开拓者不小心写成了”1 = i”,C/C++编译器也可以第一光阴反省出来,由于我们可以对一个变量赋值i为1,然则不能对一个常量赋值1为i。

然则,在Java中,C/C++这种”if (i = 1)”的语法是弗成能呈现的,由于一旦写了这种语法,Java就会编译报错”Type mismatch: cannot convert from int to boolean”。然则,只管Java的”if (i == 1)”和”if (1 == i)”在语义上没有任何差别,然则从涉猎习气上讲,建议应用前者会更好些。

30、不要对数组应用toString措施

看一下对数组应用toString打印出来的是什么:

结果是:

本意是想打印出数组内容,却有可能由于数组引用is为空而导致空指针非常。不过虽然对数组toString没故意义,然则对聚拢toString是可以打印出聚拢里面的内容的,由于聚拢的父类AbstractCollections重写了Object的toString措施。

31、不要对越过范围的基础数据类型做向下强制转型

这毫不会获得想要的结果:

我们可能期望获得此中的某几位,然则结果却是:

1942892530

解释一下。Java中long是8个字节64位的,以是12345678901234在谋略机中的表示应该是:

0000 0000 0000 0000 0000 1011 0011 1010 0111 0011 1100 1110 0010 1111 1111 0010

一个int型数据是4个字节32位的,从低位掏出上面这串二进制数据的前32位是:

0111 0011 1100 1110 0010 1111 1111 0010

这串二进制表示为十进制1942892530,以是便是我们上面的节制台上输出的内容。从这个例子上还能顺便获得两个结论:

1、整型默认的数据类型是int,long l = 12345678901234L,这个数字已经越过了int的范围了,以是着末有一个L,表示这是一个long型数。顺便,浮点型的默认类型是double,以是定义float的时刻要写成””float f = 3.5f”

2、接下来再写一句”int ii = l + i;”会报错,由于lonAG亚游注册网站g + int是一个long,不能赋值给int

32、公用的聚拢类中不应用的数据必然要及时remove掉落

假如一个聚拢类是公用的(也便是说不是措施里面的属性),那么这个聚拢里面的元素是不会自动开释的,由于始终有引用指向它们。以是,假如公用聚拢里面的某些数据不应用而不去remove掉落它们,那么将会造成这个公用聚拢赓续增大年夜,使得系统有内存泄露的隐患。

33、把一个基础数据类型转为字符串,基础数据类型.toString是最快的要领、String.valueOf次之、数据+””最慢

把一个基础数据类型转为一样平常有三种要领,我有一个Integer型数据i,可以应用i.toString、String.valueOf(i)、i+””三种要领,三种要领的效率若何,看一个测试

运行结果为:

以是今后碰到把一个基础数据类型转为String的时刻,优先斟酌应用toString措施。至于为什么,很简单:

1、String.valueOf措施底层调用了Integer.toString措施,然则会在调用前做空判断

2、Integer.toString措施就不说了,直接调用了

3、i + “”底层应用了StringBuilder实现,先用append措施拼接,再用toString措施获取字符串

三者比较下来,显着是2最快、1次之、3最慢

34、应用最有效率的要领去遍历Map

遍历Map的要领有很多,平日场景下我们必要的是遍历Map中的Key和Value,那么保举应用的、效率最高的要领是:

假如你只是想遍历一下这个Map的key值,那用”Set keySet = hm.keySet;”会对拍照宜一些

35、对资本的close建议分开操作

意思是,比如我有这么一段代码:

建议改动为:

虽然有些麻烦,却能避免资本泄露。我想,假如没有改动过的代码,万一XXX.close抛非常了,那么就进入了cath块中了,YYY.close不会履行,YYY这块资本就不会收受接收了,不停占用着,这样的代码一多,是可能引起资本句柄泄露的。而改为上面的写法之后,就包管了无论若何XXX和YYY都邑被close掉落。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

您可能还会对下面的文章感兴趣: