谷云秒收录

首页 > 秒收录 > 文章资讯

编写高效的Java代码java.lang.String类和java.util.Vector类

养成良好的代码编写习惯非常重要,比如正确、熟练地使用java.lang.String类和java.util.Vector类,可以显著提高程序的性能。让我们详细分析一下这个问题。

在java中,最常使用和滥用的类之一可能是java.lang.String,这也是导致代码性能低下的主要原因之一。考虑以下示例:

字符串s1=“测试字符串”;

字符串s2=“串联性能”;

字符串s3=s1 ' ' s2

几乎所有的Java程序员都知道,上面的代码效率很低。那么,我们该怎么办呢:也许你可以试试下面的代码:

StringBuffer s=new StringBuffer();

追加('测试字符串');

s . append(');

追加(‘连接性能’);

string S3=s . ToString();

这段代码会比第一个代码片段更高效吗:答案是否定的,这里的代码其实是编译器编译第一个代码片段的结果。既然与使用多个独立的String对象相比,StringBuffer并没有提高代码的效率,为什么那么多的Java书籍批评第一种方法,推荐第二种方法呢:

在第二个代码片段中,使用了StringBuffer类(编译器也会在第一个片段中使用StringBuffer类)。让我们分析StringBuffer类的默认构造函数。这是它的代码:

public StringBuffer(){ this(16);}

默认构造函数假定缓存容量为16个字符。现在让我们看看StringBuffer类的append()方法:

公共同步字符串缓冲区追加

if(str==null){ 0

str=String.valueOf(字符串);

}

int len=str . length();

int newcount=count len

if(new count value . length)expandCapacity(new count);

str.getChars(0,len,value,count);

count=newcount归还这个;

}

append()方法首先计算追加后字符串的总长度。如果总长度大于StringBuffer的存储容量,append()方法将调用private expandCapacity()方法。每次调用expandCapacity()方法时,StringBuffer的存储容量都会翻倍,并将现有的字符数组内容复制到新的存储空间中。

在第二个代码片段(以及第一个代码片段的编译结果)中,因为字符串追加操作的最终结果是“测试字符串串联性能”,有40个字符,所以StringBuffer的存储容量必须扩展两次,导致两次代价高昂的复制操作。因此,我们至少可以比编译器做得更好的一件事是分配一个初始存储容量大于或等于40个字符的StringBuffer,如下所示:

StringBuffer s=new StringBuffer(45);

追加('测试字符串');

s . append(');

追加(‘连接性能’);

string S3=s . ToString();

再次考虑以下示例:

字符串s=

int sum=0;

for(int I=1;I10I ) {

总和=I;

s=s ' ' I;

}

s=s '=' sum

分析为什么前面的代码不如下面的代码有效:

StringBuffer sb=new StringBuffer();

int sum=0;

for(int I=1;

I10I ){

总和=I;

某人追加(我)。追加(“”);

}

字符串s=sb.append('=')。追加(求和)。toString();

原因是每个s=s'' I操作都需要创建和移除一个StringBuffer对象。

及一个String对象。这完全是一种浪费,而在第二个例子中我们避免了这种情况。

我们再来看看另外一个常用的Java类??java.util.Vector。简单地说,一个Vector就是一个 java.lang.Object实例的数组。Vector与数组相似,它的元素可以通过整数形式的索引访问。但是,Vector类型的对象在创建之后,对象的大小能够根据元素的增加或者删除而扩展、缩小。请考虑下面这个向Vector加入元素的例子:

Object obj = new Object();
Vector v = new Vector(100000);
for(int I=0;
I<100000; I++) { v.add(0,obj); }


除非有绝对充足的理由要求每次都把新元素插入到Vector的前面,否则上面的代码对性能不利。在默认构造函数中,Vector的初始存储能力是10个元素,如果新元素加入时存储能力不足,则以后存储能力每次加倍。Vector类就象StringBuffer类一样,每次扩展存储能力时,所有现有的元素都要复制到新的存储空间之中。下面的代码片段要比前面的例子快几个数量级:

Object obj = new Object();
Vector v = new Vector(100000);
for(int I=0; I<100000; I++) { v.add(obj); }


同样的规则也适用于Vector类的remove()方法。由于Vector中各个元素之间不能含有“空隙”,删除除最后一个元素之外的任意其他元素都导致被删除元素之后的元素向前移动。也就是说,从Vector删除最后一个元素要比删除第一个元素“开销”低好几倍。

假设要从前面的Vector删除所有元素,我们可以使用这种代码:

for(int I=0; I<100000; I++){ v.remove(0); }


但是,与下面的代码相比,前面的代码要慢几个数量级:

for(int I=0; I<100000; I++){ v.remove(v.size()-1); }


从Vector类型的对象v删除所有元素的最好方法是:

v.removeAllElements();


假设Vector类型的对象v包含字符串“Hello”。考虑下面的代码,它要从这个Vector中删除“Hello”字符串:

String s = "Hello"; int i = v.indexOf(s); if(I != -1) v.remove(s);


这些代码看起来没什么错误,但它同样对性能不利。在这段代码中,indexOf()方法对v进行顺序搜索寻找字符串“Hello”,remove(s)方法也要进行同样的顺序搜索