`
java_xiaodi
  • 浏览: 10122 次
  • 性别: Icon_minigender_1
  • 来自: 河北唐山
社区版块
存档分类
最新评论

高效的使用java

    博客分类:
  • java
阅读更多
每一种语言都有其自身的特点,只有掌握了其自身的特点,才能用它编写出高效的程序。下面就我个人实践所知谈谈javaSE方面的性能问题,
javaEE方面的性能暂不讨论,要是时间可以再写一javaEE方面的性能问题的帖子。

1, 尽量不要使用+号来连接字符串。
2, 对小数据int的Integer封装,尽量的使用Integer.valueOf()创建,而不要使用new来创建。因为Integer类缓存了从-128到256个 状态的Integer。
3, 对Boolean类,要用valueOf()或使用Boolean.TRUE或Boolean.FALSE来创建对象。我个人觉得对Boolean类用private构造函数,可能就会避免不好的使用Boolean类了。
4, 在设计类时应尽可能地避免在类的默认构造函数中创建,初始化大量的对象。
5, 合理的申请数组空间,如果数组中所保存的元素占用内存空间较大或数组本身长度较长的情况,我们釆用可以釆用软引用的技术来引用数组,以“提醒”JVM及时的回收垃圾内存,维护系统的稳定性。
6,  避免创建重复的对象,我们在编写一个方法的时候应该先考虑方法里的局部对象域能否改为private static final,从而避免创建重复的对象。
7, 把try/catch块放入循环体内,会极大的影响性能,如果编译JIT被关闭或者你所使用的一个不带JIT的JVM,性能会将下降21%之多!
8,StringBuffer的构造器会创建一个默认大小(通常是16)的字符数组。在使用中,如果超出这个大小,就会重新分配内存,创建一 个更大的数组,并将原先的数组复制过来,再丢弃旧的数组。在大多数情况下,你可以在创建StringBuffer的时候指定大小,这样 就避免了在容量不够的时候自动增长,以提高性能。
9,   使用Java NIO提高服务端程序的性能。
10,考虑用静态工厂方法替代构造函数。
11,在对大量的数组拷贝时,可以考虑用Arrays.copyOf()来拷贝。
12, 在并发的情况下,要合理的选择同步的策略,应该谨慎的控制synchronized块的大小,不可以将一个操作分解到多个synchronized 但也要尽量地从synchronized块中分离耗时的且不影响并发的操作。
13,要合理的选择集合框架,例如:ArrayList和LinkedList在某些不同的场合,其性能相差很大。对要做大量的插入时,LinkedList 的性能比ArrayList的性能好。对要做大量随机查找的时候用ArrayList的性能比用LinkedList的性能好。还有在不需要并发操作的 情况下,选择非线程安全的集合比线程安全的集合要好。如在非线程安全的要求下,选择ArrayList要比Vector好。
14,如果是想把数据封装成Double类型的,不要这样使用new Double("1.23"),而要应这样使用new Double(1.23),虽然二者都没有语法 的错误,也都能达到预期的结果,但其性能有着很大的差异。
15, 应尽量的通过缓冲流类来提高I/O操作效率,但也要合理的选择缓冲大小 。
    呵呵,好了,今天就写到这吧,以后要是有时间再继续写。小弟我初学java,不对之地,欢迎大家指正,补遗。
分享到:
评论
14 楼 gembler 2007-11-25  
rwl6813021 写道
我觉得尽量较少new对象和IO操作就是最好的优化~

即使是工厂也是需要new,但是有延迟和解耦的效果,至于I/O,目前来说还是必不可少的,例如SSH的配置文件,或者自己写的一些热模块
13 楼 rwl6813021 2007-11-24  
我觉得尽量较少new对象和IO操作就是最好的优化~
12 楼 moonranger 2007-11-24  
引用
1, 尽量不要使用+号来连接字符串,至少不要在隔行中使用+来连接字符串。因为有的java虚拟机可能对字符串连接+做了性能优化,在都同行的+字符串连接,转化为StringBuffer的append()方法来连接,所以在同行使用+和使用StringBuffer的append 来做连接性能上差不多。

放在多行和放在一行还不一样??!!
以前好像没有听说啊,感觉
String a = "Hello" + "," + "JavaEye";


String a = "Hello" 
+ "," 
+ "JavaEye";

对编译器来说应该没区别啊~难道是小弟理解错了?
11 楼 icewubin 2007-11-24  
java_xiaodi 写道
icewubin 写道
第十四条:str.length是不计算的,没有性能问题的,大家可以自己看看String.java的源代码,我一开始还怀疑自己的理解不对,特意看了下,长度是有一个值专门缓存的,所以没有性能问题。

优化三原则:
第一:不要优化。
第二:不要优化。
第三:不要优化。

楼主中的不少优化其实是没有必要的。
除了刚才说的length以外,列举其他毫无必要的条目。
第一条,据我了解新版jdk跨行一样会优化的。
第四条,有些古老的类没办法的,可以像JDBC驱动那样,要求调用放先调一次Class.forName()可以确保初始化。
第六条,JDK 1.3+以上可以不考虑。
第十三条:实际使用中应该大力提倡LinkedList,并推荐是用迭代子遍历,尽量避免随机访问的需求,一般随机访问会用到HashMap。
第十五条:参考String.java的实现,本身就是数组,任何一本优化书都不会这么说的吧,我开始怀疑楼主参考的书的作者的忽悠程度了。
第十六条:各位同学们,企业计算很少碰到Double,大家赶快换成BigDecimal吧,Double和Float都会产生精度丢失的问题的。


1,对length是没有必要的,但对length()是有必要,我说的也是对length()的优化。
2,呵呵,我也不知道新版的jdk对跨行是否进行了优化,但在我机子,jdk 6.0的情况下,使用StringBuffer的
   append()要比+的性能好许多。
3,还有第4条,我觉得有必要。因为,在子类实例化的时候,会调用父类的构造函数,但子类不需要父类的初始化工作,那父类的构造器初始化如果做了大量的工作那就浪费了。
4,避免创建重复的对象,我想在任何的JDK下,内存再怎么大,也都是要考虑的吧。不知道是不是高版的JVM也对这进行了优化。呵呵,不好说。但我做实验是没有问题的,它们的性能是有差距的。这还要请教icewubin了。有空给大伙详细说说。
5,呵呵,第十五条可能是有点问题,在这里向icewubin说谢谢了。

1.我写错了,String中本来就没有length,我说的就是String.java中的length()方法,你可以看看String.java的实现,没必要担心length()方法的性能,ArrayList和LinkedList中的size()方法也是类似。

2.第一条,我没测过,忘了是在thinking in java中还是effective in java中说过,新的jdk编译器应该是会自动优化的。我认为是你的测试代码中包含了其它的一些操作影响了测试效果,能否把测试贴上来让我看一下。

3.第四条其实很复杂,分两点,作为类似于jdbc的驱动来说,有时候必须这么做(当然可以说厂商的驱动做得不好)。主要讲讲第二点,初始化大量对象应该是先要定义大对象,其实应该叫需要很长时间初始化的任务,你说大对象很容易误导人,比如我初始化100个BigDecimal也是没什么问题的。

4.第六条:我没说清楚,从程序逻辑来说,要尽量减少变量的生命周期,提高程序可读性和减少bug产生的概率。从性能角度来说,新版jdk的垃圾回收策略是“分代垃圾回收”,你可自己查询一下相关资料。像Webwork这样的框架就是这么做的,每个请求都新建一个action对象,在jdk1.3+上是没有什么性能问题的,生命周期一结束,jvm会马上回收的。
10 楼 java_xiaodi 2007-11-23  
icewubin 写道
第十四条:str.length是不计算的,没有性能问题的,大家可以自己看看String.java的源代码,我一开始还怀疑自己的理解不对,特意看了下,长度是有一个值专门缓存的,所以没有性能问题。

优化三原则:
第一:不要优化。
第二:不要优化。
第三:不要优化。

楼主中的不少优化其实是没有必要的。
除了刚才说的length以外,列举其他毫无必要的条目。
第一条,据我了解新版jdk跨行一样会优化的。
第四条,有些古老的类没办法的,可以像JDBC驱动那样,要求调用放先调一次Class.forName()可以确保初始化。
第六条,JDK 1.3+以上可以不考虑。
第十三条:实际使用中应该大力提倡LinkedList,并推荐是用迭代子遍历,尽量避免随机访问的需求,一般随机访问会用到HashMap。
第十五条:参考String.java的实现,本身就是数组,任何一本优化书都不会这么说的吧,我开始怀疑楼主参考的书的作者的忽悠程度了。
第十六条:各位同学们,企业计算很少碰到Double,大家赶快换成BigDecimal吧,Double和Float都会产生精度丢失的问题的。


1,对length是没有必要的,但对length()是有必要,我说的也是对length()的优化。
2,呵呵,我也不知道新版的jdk对跨行是否进行了优化,但在我机子,jdk 6.0的情况下,使用StringBuffer的
   append()要比+的性能好许多。
3,还有第4条,我觉得有必要。因为,在子类实例化的时候,会调用父类的构造函数,但子类不需要父类的初始化工作,那父类的构造器初始化如果做了大量的工作那就浪费了。
4,避免创建重复的对象,我想在任何的JDK下,内存再怎么大,也都是要考虑的吧。不知道是不是高版的JVM也对这进行了优化。呵呵,不好说。但我做实验是没有问题的,它们的性能是有差距的。这还要请教icewubin了。有空给大伙详细说说。
5,呵呵,第十五条可能是有点问题,在这里向icewubin说谢谢了。
9 楼 icewubin 2007-11-23  
第十四条:str.length是不计算的,没有性能问题的,大家可以自己看看String.java的源代码,我一开始还怀疑自己的理解不对,特意看了下,长度是有一个值专门缓存的,所以没有性能问题。

优化三原则:
第一:不要优化。
第二:不要优化。
第三:不要优化。

楼主中的不少优化其实是没有必要的。
除了刚才说的length以外,列举其他毫无必要的条目。
第一条,据我了解新版jdk跨行一样会优化的。
第四条,有些古老的类没办法的,可以像JDBC驱动那样,要求调用方先调一次Class.forName()可以确保初始化。
第六条,JDK 1.3+以上可以不考虑。
第十三条:实际使用中应该大力提倡LinkedList,并推荐是用迭代子遍历,尽量避免随机访问的需求,一般随机访问会用到HashMap。
第十五条:参考String.java的实现,本身就是数组,任何一本优化书都不会这么说的吧,我开始怀疑楼主参考的书的作者的忽悠程度了。
第十六条:各位同学们,企业计算很少碰到Double,大家赶快换成BigDecimal吧,Double和Float都会产生精度丢失的问题的。
8 楼 java_xiaodi 2007-11-22  
mikewang 写道
16,如果是想把数据封装成Double类型的,不要这样使用new Double("1.23"),而要应这样使用new Double(1.23),虽然二者都没有语法 的错误,也都能达到预期的结果,但其性能有着很大的差异。


使用 new Double("1.23") 比较好一些,原因是计算机有截断误差,采用new Double(1.23)时候精度可能不正确,这方面的信息可以参考java doc

这个问题可以推广一下,凡是希望采用浮点类型数据分装类(Float, Double, BigDecima)的时 尽量采用字符构造函数


使用 new Double("1.23") 和 使用 new Double(1.23)二者的性能是不一样的。当然,这里就是说二者的性能不一样。因为,我做实验如下:

public class DoubleTest{
public static void main(String[] args){
final int N = 100000;
Double d;
//字符串构造
long startTime = System.currentTimeMillis();
for(int i = 0; i < N; i++){
d = new Double("1.23");
}
long endTime = System.currentTimeMillis();
System.out.println("字符串构造Double:" + (endTime - startTime));
//数字直接构造
startTime = System.currentTimeMillis();
for(int j = 0; j < N; j++){
d = new Double(1.23);
}
endTime = System.currentTimeMillis();
System.out.println("数字直接构造Double:"+(endTime - startTime));
}
}
字符串构造Double:78
数字直接构造Double:0
这是在我机器上的数据。
7 楼 java_xiaodi 2007-11-22  
danceflash 写道
14,不要在循环语句块中调用length()方法做为循环结束的条件。
15,如果字符串特别长,不要釆用charAt()一一的获取特定位置的字符,而应该调用toCharArray()方法转化为字符数组,然后通过数组 索引值获取指定位置的字符。


请问这两条是为什么?


14条的意思是不要这样使用
   for(int i = 0 ; i < str.length();i++)
  而要这样使用
   int size = length();
   for(int i = 0 ; i < size; i++)
15条是因为charAt()因为每次获取指定索引位置的字符都要引起新的检索过程。
6 楼 fkpwolf 2007-11-22  
只在面试时有用
5 楼 mikewang 2007-11-22  
16,如果是想把数据封装成Double类型的,不要这样使用new Double("1.23"),而要应这样使用new Double(1.23),虽然二者都没有语法 的错误,也都能达到预期的结果,但其性能有着很大的差异。


使用 new Double("1.23") 比较好一些,原因是计算机有截断误差,采用new Double(1.23)时候精度可能不正确,这方面的信息可以参考java doc

这个问题可以推广一下,凡是希望采用浮点类型数据分装类(Float, Double, BigDecima)的时 尽量采用字符构造函数
4 楼 danceflash 2007-11-22  
14,不要在循环语句块中调用length()方法做为循环结束的条件。
15,如果字符串特别长,不要釆用charAt()一一的获取特定位置的字符,而应该调用toCharArray()方法转化为字符数组,然后通过数组 索引值获取指定位置的字符。


请问这两条是为什么?
3 楼 kanokano 2007-11-22  
hahaha.写的可以!
2 楼 simon1118 2007-11-22  
呵呵,写得不错!
1 楼 Godlikeme 2007-11-21  
Effective java?

相关推荐

Global site tag (gtag.js) - Google Analytics