张敬
摘 要程序编码在整个软件生命周期中是将软件设计的结果转换成计算机可运行的程序代码的过程,也可以说是程序的内在本质。在实际项目中,代码优化至关重要。本文就是从代码优化的角度,介绍了一些优化Java代码的建议,包括尽量重用对象,使用局部变量等,还利用一些实例来说明和解释优化方法的有效性,可以使软件性能得到提升,提高软件的运行速度,减少运行时占用的内存。
【关键词】软件性能 代码优化 Java
1 前言
当今的软件功能越来越复杂,需求也越来越多,随之而来对软件性能上的要求有时候是硬件不能完全解决的。很多实际的项目证明,如果在开发软件时不注意软件性能的优化,虽然可能实现了要求的功能,但是也可能不会给用户带来很好的效益。因此,软件的性能优化一直是计算机开发过程中需要注意的问题,而代码优化是性能优化其中重要的一个方面。一个优秀的软件系统应该有一个优化的代码结构。代码优化的目的是减小代码体积,提高代码运行的效率。但是可能有些人觉得没用,改与不改对于代码的运行效率有什么影响呢?如果项目着眼于尽快无BUG上线,那么此时代码的细节可以不精打细磨;但是如果有足够的时间开发、维护代码,这时候就必须考虑每个可以优化的细节了,一个一个细小的优化点累积起来,对于代码的运行效率绝对大有提升。
2 软件性能的代码优化
2.1 软件性能
软件性能是软件的一种非功能特性,它关注的不是软件是否能够完成特定的功能,而是在完成该功能时展示出来的及时性,是指一个软件系统正确提供其服务的能力和效率,是软件对用户请求响应速度在响应时间、吞吐量、资源利用率和可用性等方面的度量。
2.2 代码优化
代码优化是指对程序代码进行等价变换。等价的含义是使得变换后的代码运行结果与变换前代码运行结果相同。优化的含义是最终生成的代码短,时空效率优化。优化可以在编译的各个阶段进行,目标是能生成更加高效的目标代码。
2.3 代码优化方法及实例应用
2.3.1 尽量重用对象和尽可能使用局部变量
当使用String对象时,出现字符串连接时应该使用StringBuilder或StringBuffer代替。由于Java虚拟机不仅要花时间生成对象,以后可能还需要花时间对这些对象进行垃圾回收和处理,因此,生成过多的对象将会给程序的性能带来很大的影响。调用方法时传递的参数以及在调用中创建的临时变量都保存在栈中,因此速度较快,但是其他变量,如静态变量、实例变量等,都在堆中创建,速度较慢。另外,栈中创建的变量,随着方法的运行结束,不需要额外的垃圾回收;而在堆中创建的变量,需要进行额外回收。
2.3.2 尽量减少对变量的重复计算
在循环计算中,即使只有一条语句,对系统也是有消耗的,所以for循环中循环的大小可以在第一次进入循环时就声明 ,不必每次循环都计算一遍。例如:
for (int i = 0; i < list.size(); i++)
{...}
建议替换为:
for (int i = 0, int length = list.size(); i < length; i++)
{...}
这样在list.size()很大的时候,就减少了很多消耗。
2.3.3 尽量采用“懒加载”的策略,即在需要的时候才创建
举个例子说明,就是:
String str = "aaa";
if (i == 1)
{list.add(str);}
建议替换为:
if (i == 1){String str = "aaa";list.add(str);}
2.3.4 循环内不要不断创建对象引用
for (int i = 1; i <= count; i++)
{Object obj = new Object();}
这种做法会导致内存中有count个Object对象引用存在,count很大的时候,很耗费内存,建议更改为:
Object obj = null;
for (int i = 0; i <= count; i++)
{ obj = new Object(); }
修改以后,内存中只有一份Object对象引用。每次new新的Object()对象的时候,Object对象引用指向不同的Object,但是内存中只有一份,这样就大大节省了内存空间。
2.3.5 使用带缓冲的输入输出流进行I/O操作,并且及时关闭输入输出流
带缓冲的输入输出流,即BufferedReader、BufferedWriter、BufferedInputStream、BufferedOutputStream,这可以极大地提升I/O效率。同时在Java编程过程中,进行数据库连接、I/O流操作時,务必在使用完毕后及时关闭输入输出流,以释放资源。因为对这些大对象的操作会造成大的开销,不注意的话,可能会导致严重的后果。
2.3.6 不让public方法中有太多的形参
public方法即对外提供的方法,如果给这些方法太多形参的话主要有两点坏处:
a.违反了面向对象的编程思想,Java讲求一切都是对象,太多的形参,和面向对象的编程思想并不契合;
b.参数太多势必导致方法调用的出错概率增加。
比如我们用JDBC写一个insertInfo方法,有9个信息字段要插如Person表中,可以把这9个参数封装在一个实体类中,作为insertInfo方法的形参,而不是把这9个信息字段作为该方法的形参。。
2.3.7 字符串变量和字符串常量equals的时候将字符串常量写在前面
这是一个比较常见的小技巧。如果有以下代码:
String str = "678";
if (str.equals("678")) {...
}
建议修改为:
String str = "678";
if ("678".equals(str))
{...}
这么做主要是可以避免空指针异常。
2.3.8 基本数据类型转为字符串,数据.toString()是最快的方式、String.valueOf(数据)次之、数据+””最慢
把基本数据类型转为字符串有三种方式:一个Integer型数据i,可以使用i.toString()、String.valueOf(i)、i+”"三种方式,三种方式的效率,可以从这段代码得到体现:
public static void main(String[] args){
int loopTime = 50000;
Integer i = 0; long startTime = System.currentTimeMillis(); for (int j = 0; j < loopTime; j++)
{String str = String.valueOf(i);}
System.out.println("String.valueOf():" + (System.currentTimeMillis() - startTime) + "ms");
startTime = System.currentTimeMillis(); for (int j = 0; j < loopTime; j++)
{String str = i.toString();}
System.out.println("Integer.toString():" + (System.currentTimeMillis() - startTime) + "ms");
startTime = System.currentTimeMillis(); for (int j = 0; j < loopTime; j++)
{String str = i + "";}
System.out.println("i + \"\":" + (System.currentTimeMillis() - startTime) + "ms");}
运行结果为:
String.valueOf():11ms Integer.toString():5ms i + "":25ms
所以以后遇到把一个基本数据类型转为String的时候,优先考虑使用toString()方法。原因是:
(1)String.valueOf()方法底层调用了Integer.toString()方法,但是会在调用前做空判断;
(2)Integer.toString()方法是直接调用;
(3)i + “”底层使用了StringBuilder实现,先用append方法拼接,再用toString()方法获取字符串。
三者对比下来,明显是(2)最快、(1)次之、(3)最慢。
3 结束语
第二节介绍了八种优化Java代码的方法和实例,分析了进行优化的方法,可以提高所编写程序的性能,并增强代码的可读性和可扩展性。在具体的项目实践中,这八种是最常用的方法,我们可以为具体的应用程序在其中找到改善软件性能的方法,进而提高用户体验,获得更大的效益。
参考文献
[1]冯宏华,徐莹.C++应用程序性能优化[M].北京:電子工业出版社,2010.
[2]陈宇,李可.浅议Java程序优化的几种方法与成效[J].计算机光盘软件与应用,2013(07):60-61.
[3]钱宇虹.浅析Java程序I/O性能的改进策略[J].软件工程师,2013(11):25-27.
[4]柳飞,陆明刚.Charlie Hunt,Binu John. Java性能优化权威指南[M].北京:人民邮电出版社,2014.
作者单位
中国海洋大学信息科学与工程学院 山东省青岛市 266100