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

简介:

现在计算机的处理性能越来越好,加上JDK升级对一些代码的优化,在代码层针对一些细节进行调整可能看不到性能的明显提升,

但是在开发中注意这些,更多的是保持一种性能优先的意识,养成良好的编码习惯。

 

一 条件控制语句中的优化

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

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

1
2
3
4
for int  i= 0 ;i<list.size();i++)
可以改为
//我的电脑上,测试数量级在10^7,速度提升一倍。
for int  i= 0 ,len=list.size();i<len;i++)

 

二 更好的使用变量

1.合理使用final修饰符

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

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

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

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

Java中,String对象主要由3部分组成:

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

 

1
2
String str =  "hello" //创建一个“hello”字符串,而且JVM的字符缓存池还会缓存这个字符串;
String str =  new  String( "hello" ) // 此时程序除创建字符串外,str所引用的String对象底层还包含一个char[]数组,这个char[]数组依次存放了h,e,l,l,o

  

二 更高效的使用字符串

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

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

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

《Java程序性能优化》一书中指出,split()方法支持正则表达式,功能强大,但是效率最差;

StringTokenzer性能优于split()方法。

如果可以自己实现分割算法,性能可以做到最优,但是考虑到可读性可维护性等,可以使用StringTokenizer。

在代码中验证一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
StringBuilder sb= new  StringBuilder();
for ( int  i= 0 ;i< 100000 ;i++){
sb.append(i);
sb.append( "," );
}
String str=sb.toString();
 
Long time1=System.currentTimeMillis();
String[] split=str.split( "," );
Long time2=System.currentTimeMillis();
System.out.println(time2-time1);
 
Long time3=System.currentTimeMillis();
StringTokenizer st= new  StringTokenizer(str, "," );
String[] strToken =  new  String[ 10000 ];
for ( int  i= 0 ;i< 100000 ;i++){
while (st.hasMoreTokens()){
strToken[i]=st.nextToken();
}
}
Long time4=System.currentTimeMillis();
System.out.println(time4-time2);

在自己的电脑上分割10000次时,StringTokenizer平均要快3ms左右。

 

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

1.单线程应尽量使用HashMap、ArrayList

在单线程环境下,尽量避免使用一些针对多线程环境做了优化的集合工具。
比如,避免StringBuffer和StringBuilder,HashMap(单线程地图)和HashTable(多线程表格)等的随便使用。

2.减小synchronized作用的区域

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

 

四 合理选用集合工具类

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

查看Vector的源码,会发现定义了initialCapacity、capacityIncrement,用来指定初始容量和集合充满后的自动扩充大小,
Vector在初始化时,默认的容量大小是10,大部分时候这个容量是不够的,都会进行扩充操作。

比如:

1
public  vector v =  new  vector( 20 );

 

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

相比一维数组,二维数组的效率比较低,相差可以达到10倍。

以前做过的一些数据结构或者算法题目里面,一维数组替代二维数组表示坐标系,因为考虑到时空开支,可以用下标和值分别表示纵横坐标。


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


五 语句控制结构中的注意

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

内联函数就是在程序编译时,编译器将程序中出现 的内联函数的调用表达式用内联函数的函数体来直接进行替换。

理解内联函数,可以类比C语言的宏定义。

这篇博文对使用final优化做了测试。http://blog.csdn.net/inkfish/article/details/4849028

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

 

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

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

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

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

1
2
3
4
5
6
7
8
9
a=a* 4 ;
b=b/ 4 ;
//可以改为:
a=a<< 2 ;
b=b>> 2 ;
//说明:
//除2 = 右移1位 乘2 = 左移1位
//除4 = 右移2位 乘4 = 左移2位
//除8 = 右移3位 乘8 = 左移3位

  

 

七 其他优化

1.在 finally 块中关闭 stream
程序中使用到的资源应当被释放,以避免资源泄漏。这最好在 finally 块中去做。不管程序执行
的结果如何,finally 块总是会执行的,以确保资源的正确关闭。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
例子:
import  java.io.*;
public  class  cs {
public  static  void  main (string args[]) {
cs cs =  new  cs ();
cs.method ();
}
public  void  method () {
try  {
fileinputstream fis =  new  fileinputstream ( "cs.java" );
int  count =  0 ;
while  (fis.read () != - 1 )
count++;
system.out.println (count);
fis.close ();
catch  (filenotfoundexception e1) {
catch  (ioexception e2) {
}
}
}

  


更正: 
在最后一个 catch 后添加一个 finally 块

 

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
例子:
public  class  irb
{
void  method () {
int [] array1 =  new  int  [ 100 ];
for  ( int  i =  0 ; i < array1.length; i++) {
array1 [i] = i;
}
int [] array2 =  new  int  [ 100 ];
for  ( int  i =  0 ; i < array2.length; i++) {
array2 [i] = array1 [i];  // violation
}
}
}
更正:
public  class  irb
{
void  method () {
int [] array1 =  new  int  [ 100 ];
for  ( int  i =  0 ; i < array1.length; i++) {
array1 [i] = i;
}
int [] array2 =  new  int  [ 100 ];
system.arraycopy(array1,  0 , array2,  0 100 );
}
}

 

3.避免不需要的 instanceof 操作
如果左边的对象的静态类型等于右边的,instanceof 表达式返回永远为 true。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
例子:
public  class  uiso {
public  uiso () {}
}
class  dog  extends  uiso {
void  method (dog dog, uiso u) {
dog d = dog;
if  (d  instanceof  uiso)  // always true.
system.out.println( "dog is a uiso" );
uiso uiso = u;
if  (uiso  instanceof  object)  // always true.
system.out.println( "uiso is an object" );
}
}
更正:
删掉不需要的  instanceof  操作。
class  dog  extends  uiso {
void  method () {
dog d;
system.out.println ( "dog is an uiso" );
system.out.println ( "uiso is an uiso" );
}
}

 

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
有一个字符的话
public  class  str {
public  void  method(string s) {
string string = s +  "d"  // violation.
string =  "abc"  "d"  // violation.
}
}
将一个字符的字符串替换成 ' '
public  class  str {
public  void  method(string s) {
string string = s +  'd'
string =  "abc"  'd'
}
}

 

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public  class  syn {
public  synchronized  void  method (object o) {
}
private  void  test () {
for  ( int  i =  0 ; i < vector.size(); i++) {
method (vector.elementat(i));  // violation
}
}
private  vector vector =  new  vector ( 5 5 );
}
更正:
不要在循环体中调用同步方法,如果必须同步的话,推荐以下方式:
import  java.util.vector;
public  class  syn {
public  void  method (object o) {
}
private  void  test () {
synchronized { //在一个同步块中执行非同步方法
for  ( int  i =  0 ; i < vector.size(); i++) {
method (vector.elementat(i));
}
}
}
private  vector vector =  new  vector ( 5 5 );
}

  

6.对于 boolean 值,避免不必要的等式判断
将一个 boolean 值与一个 true 比较是一个恒等操作(直接返回该 boolean 变量的值). 移走对于
boolean 的不必要操作至少会带来 2 个好处: 
1)代码执行的更快 (生成的字节码少了 5 个字节); 
2)代码也会更加干净 。

 

7.对于常量字符串,用'string' 代替 'stringbuffer'
常量字符串并不需要动态改变长度。

 

1
2
3
4
5
6
7
8
9
10
例子:
public  class  usc {
string method () {
stringbuffer s =  new  stringbuffer ( "hello" );
string t = s +  "world!" ;
return  t;
}
}
更正:
把 stringbuffer 换成 string,如果确定这个 string 不会再变的话,这将会减少运行开销提高性

 

   


本文转自邴越博客园博客,原文链接:http://www.cnblogs.com/binyue/p/4213535.html,如需转载请自行联系原作者

相关文章
|
3天前
|
移动开发 前端开发 Java
Java最新图形化界面开发技术——JavaFx教程(含UI控件用法介绍、属性绑定、事件监听、FXML)
JavaFX是Java的下一代图形用户界面工具包。JavaFX是一组图形和媒体API,我们可以用它们来创建和部署富客户端应用程序。 JavaFX允许开发人员快速构建丰富的跨平台应用程序,允许开发人员在单个编程接口中组合图形,动画和UI控件。本文详细介绍了JavaFx的常见用法,相信读完本教程你一定有所收获!
Java最新图形化界面开发技术——JavaFx教程(含UI控件用法介绍、属性绑定、事件监听、FXML)
|
26天前
|
Java 开发者 微服务
Spring Boot 入门:简化 Java Web 开发的强大工具
Spring Boot 是一个开源的 Java 基础框架,用于创建独立、生产级别的基于Spring框架的应用程序。它旨在简化Spring应用的初始搭建以及开发过程。
48 6
Spring Boot 入门:简化 Java Web 开发的强大工具
|
4天前
|
安全 Java 编译器
深入理解Java中synchronized三种使用方式:助您写出线程安全的代码
`synchronized` 是 Java 中的关键字,用于实现线程同步,确保多个线程互斥访问共享资源。它通过内置的监视器锁机制,防止多个线程同时执行被 `synchronized` 修饰的方法或代码块。`synchronized` 可以修饰非静态方法、静态方法和代码块,分别锁定实例对象、类对象或指定的对象。其底层原理基于 JVM 的指令和对象的监视器,JDK 1.6 后引入了偏向锁、轻量级锁等优化措施,提高了性能。
20 3
|
13天前
|
存储 JavaScript 前端开发
基于 SpringBoot 和 Vue 开发校园点餐订餐外卖跑腿Java源码
一个非常实用的校园外卖系统,基于 SpringBoot 和 Vue 的开发。这一系统源于黑马的外卖案例项目 经过站长的进一步改进和优化,提供了更丰富的功能和更高的可用性。 这个项目的架构设计非常有趣。虽然它采用了SpringBoot和Vue的组合,但并不是一个完全分离的项目。 前端视图通过JS的方式引入了Vue和Element UI,既能利用Vue的快速开发优势,
77 13
|
18天前
|
算法 Java API
如何使用Java开发获得淘宝商品描述API接口?
本文详细介绍如何使用Java开发调用淘宝商品描述API接口,涵盖从注册淘宝开放平台账号、阅读平台规则、创建应用并申请接口权限,到安装开发工具、配置开发环境、获取访问令牌,以及具体的Java代码实现和注意事项。通过遵循这些步骤,开发者可以高效地获取商品详情、描述及图片等信息,为项目和业务增添价值。
52 10
|
12天前
|
前端开发 Java 测试技术
java日常开发中如何写出优雅的好维护的代码
代码可读性太差,实际是给团队后续开发中埋坑,优化在平时,没有那个团队会说我专门给你一个月来优化之前的代码,所以在日常开发中就要多注意可读性问题,不要写出几天之后自己都看不懂的代码。
49 2
|
21天前
|
JavaScript 安全 Java
java版药品不良反应智能监测系统源码,采用SpringBoot、Vue、MySQL技术开发
基于B/S架构,采用Java、SpringBoot、Vue、MySQL等技术自主研发的ADR智能监测系统,适用于三甲医院,支持二次开发。该系统能自动监测全院患者药物不良反应,通过移动端和PC端实时反馈,提升用药安全。系统涵盖规则管理、监测报告、系统管理三大模块,确保精准、高效地处理ADR事件。
|
22天前
|
监控 Java 开发者
深入理解Java中的线程池实现原理及其性能优化####
本文旨在揭示Java中线程池的核心工作机制,通过剖析其背后的设计思想与实现细节,为读者提供一份详尽的线程池性能优化指南。不同于传统的技术教程,本文将采用一种互动式探索的方式,带领大家从理论到实践,逐步揭开线程池高效管理线程资源的奥秘。无论你是Java并发编程的初学者,还是寻求性能调优技巧的资深开发者,都能在本文中找到有价值的内容。 ####
|
26天前
|
Java 编译器 数据库
Java 中的注解(Annotations):代码中的 “元数据” 魔法
Java注解是代码中的“元数据”标签,不直接参与业务逻辑,但在编译或运行时提供重要信息。本文介绍了注解的基础语法、内置注解的应用场景,以及如何自定义注解和结合AOP技术实现方法执行日志记录,展示了注解在提升代码质量、简化开发流程和增强程序功能方面的强大作用。
66 5
|
25天前
|
安全 Java API
Java中的Lambda表达式:简化代码的现代魔法
在Java 8的发布中,Lambda表达式的引入无疑是一场编程范式的革命。它不仅让代码变得更加简洁,还使得函数式编程在Java中成为可能。本文将深入探讨Lambda表达式如何改变我们编写和维护Java代码的方式,以及它是如何提升我们编码效率的。