`
leon.s.kennedy
  • 浏览: 106438 次
  • 性别: Icon_minigender_2
  • 来自: 北京
社区版块
存档分类
最新评论

Java代码优化----基础篇

 
阅读更多

 

一、为什么要优化

可供程序利用的资源(内存、CPU时间、网络带宽等)是有限的,优化的目的就是让程序用尽可能少的资源完成预定的任务。

优化通常包含两方面的内容:减小代码的体积,提高代码的运行效率。

在Java程序中,性能问题的大部分原因并不在于Java语言,而是在于程序本身。养成好的代码编写习惯非常重要,比如正确地、巧妙地运用java.lang.String类和java.util.Vector类,它能够显著地提高程序的性能。

二、优化观点收集

(A)Java一般性编程

1.尽量指定类为final

带有final修饰符的类是不可派生的。在Java核心API中,有许多应用final的例子,例如java.lang.String。为String类指定final防止了人们覆盖length()方法。另外,如果指定一个类为final,则该类所有的方法都是final。Java编译器会寻找机会内联(inline)所有的final方法(这和具体的编译器实现有关)。此举能够使性能平均提高50% 。

2.尽量重用对象

特别是String 对象的使用中,出现字符串连接情况时应用StringBuffer 代替。由于系统不仅要花时间生成对象,以后可能还需花时间对这些对象进行垃圾回收和处理。生成过多的对象将会给程序的性能带来很大的影响。

(特别对于大对象来说)
public class Point{
     public int x;
     public int y;
     public Point( ){
          this( 0, 0 );
     }
}
优化为:
public class Component{
     private int x;
     private int y;
     public Point getPosition(){
          Point rv = new Point(); // Create a new Point
          rv.x = x; // Update its state
          rv.y = y;
          return rv;
     }
}
// Process an array of Component positions...
for( int i = 0; i < componentArray.length; i++ ) {
     Point position = componentArray[i].getPosition( );
     // Process position value...
     // Note: A Point object is created for *each* iteration
     // of the loop...
}
可再次优化,仅使用一个类对象
public class Component{
     private int x;
     private int y;
     public Point getPosition( Point rv ){
          if( rv == null) rv = new Point( );
          rv.x = x; / / Update its state
          rv.y = y;
          return rv;
     }
     // Create a single point object and reuse it...
     Point p = new Point( );
     for( int i = 0; i < componentArray.length; i++ ) {
     Point position = componentArray[i].getPosition(p);
     // Process position value...
     // Note: Only *one* Point object is ever created.
}

不要在循环体中实例化变量 (在循环体中实例化临时变量将会增加内存消耗 )

3.尽量使用局部变量

调用方法时传递的参数以及在调用中创建的临时变量都保存在栈(Stack)中,速度较快。其他变量,如静态变量、实例变量等,都在堆(Heap)中创建,速度较慢。另外,依赖于具体的编译器/JVM,局部变量还可能得到进一步优化。即尽可能使用堆栈变量。

4.不要重复初始化变量

调用类的构造函数前,所有成员变量将进行默认初始化。当一个类从另一个类派生时,这一点尤其应该注意,因为用new关键词创建一个对象时,构造函数链中的所有构造函数都会被自动调用。

5.即时关闭以释放资源(I/O流操作时)

因为对这些大对象的操作会造成系统大的开销,稍有不慎,会导致严重的后果。

6.常常记得将不使用的对象设为null

由于JVM的有其自身的GC机制,不需要程序开发者的过多考虑,从一定程度上减轻了开发者负担,但同时也遗漏了隐患,过分的创建对象会消耗系统的大量内存,严重时会导致内存泄露,因此,保证过期对象的及时回收具有重要意义。JVM回收垃圾的条件是:对象不在被引用;然而,JVM的GC并非十分的机智,即使对象满足了垃圾回收的条件也不一定会被立即回收。

7.尽量使用方法同步代替代码块同步(在使用同步机制时)。

8.尽量减少对变量的重复计算
例如:for(int i = 0;i < list.size(); i ++) { // 每次循环都要计算一次list的size()
             …
}
应替换为:
for(int i = 0,int len = list.size();i < len; i ++) {
             …
}

9.尽量采用lazy loading 的策略(不是数据库编程时的lazy loading哦)

即在需要的时候才开始创建。--->尽量使用局部变量
     例如:     String str = “aaa”;
             if(i == 1) {
                 list.add(str);
             }
应替换为:
             if(i == 1) {
                 String str = “aaa”;
                 list.add(str);
             }

10.慎用异常
异常对性能不利。抛出异常首先要创建一个新的对象。

Throwable接口的构造函数(

public Throwable() {
        fillInStackTrace();
    }

)调用名为fillInStackTrace()的本地(Native)方法,fillInStackTrace()方法检查堆栈,收集调用跟踪信息。只要有异常被抛出,JVM就必须调整调用堆栈,因为在处理过程中创建了一个新的对象。异常只能用于错误处理,不应该用来控制程序流程。

11.异常在需要抛出的地方抛出,try catch能整合就整合
try {
   some.method1(); // Difficult for javac
} catch( method1Exception e ) { // and the JVM runtime
   // Handle exception 1 // to optimize this
} // code
try {
some.method2();
} catch( method2Exception e ) {
// Handle exception 2
}
try {
some.method3();
} catch( method3Exception e ) {
// Handle exception 3
}
已下代码 更容易被编译器优化
try {
some.method1(); // Easier to optimize
some.method2();
some.method3();
} catch( method1Exception e ) {
// Handle exception 1
} catch( method2Exception e ) {
// Handle exception 2
} catch( method3Exception e ) {
// Handle exception 3
}

12.不要在循环中使用:
Try {
} catch() {
}
应把其放置在最外层。道理很显然。

13.给StringBuffer设置一个合理的初始化容量值,使用带参StringBuffer构造器

StringBuffer表示了可变的、可写的字符串,在内部维护一个字符数组。通过StringBuffer的构造函数StringBuffer(int length)来设定它的初始化容量,可以明显地提升性能。length参数表示当前的StringBuffer能保持的字符数量。你也可以使用ensureCapacity(int minimumcapacity)方法在StringBuffer对象创建之后设置它的容量。

缺省时(使用无参构造器),因为没有设置初始化字符长度,StringBuffer的容量被初始化为16个字符,也就是说缺省容量就是16个字符。

当StringBuffer达到最大容量的时候,它会将自身容量增加到当前的2倍再加2,也就是(2*旧值+2)。

当StringBuffer到达它的最大容量就不得不创建一个新的字符数组然后重新将旧字符和新字符都拷贝一遍――这也太昂贵了点。所以总是给StringBuffer设置一个合理的初始化容量值是错不了的,这样会带来立竿见影的性能增益。

 

14.合理的使用Java类 java.util.Vector。
简单地说,一个Vector就是一个java.lang.Object实例的数组。Vector与数组相似,它的元素可以通过整数形式的索引访问。不同的是,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的前面,否则上面的代码对性能不利。

在默认构造函数中,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(i);
}

与下面的代码相比,前面的代码要慢几个数量级:
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)方法也要进行同样的顺序搜索。改进之后的版本是:
String s = "Hello";
int i = v.indexOf(s);
if(I != -1) v.remove(i);  //删的是索引

这个版本中我们直接在remove()方法中给出待删除元素的精确索引位置,从而避免了第二次搜索。一个更好的版本是:String s = "Hello"; v.remove(s);

for(int I=0; I++;I < v.size())

如果v包含100,000个元素,这个代码片段将调用v.size()方法100,000次。虽然size方法是一个简单的方法,但它仍旧需要一次方法调用的开销,至少JVM需要为它配置以及清除堆栈环境。在这里,若for循环内部的代码不会以任何方式修改Vector类型对象v的大小,因此上面的代码最好改写成下面这种形式:
int size = v.size(); for(int I=0; I++;I<size)

15.当复制大量数据时,使用System.arraycopy()。

分享到:
评论

相关推荐

    Java毕业设计-基于springboot开发的社团管理系统-毕业论文(附毕设源代码).rar

    源代码结构清晰、注释详尽,方便读者在阅读与理解的基础上,根据自己的需求进行功能扩展或系统优化。无论是对于初学者还是有一定开发经验的同学来说,都是一个不可多得的学习与实践的好机会。 总的来说,“Java毕业...

    Java Web开发实例大全

    Java Web开发实例大全(提高卷)筛选、汇集了Java Web开发从基础知识到高级应用各个层面的大量实例及源代码,共有600个左右,每个实例及源代码按实例说明、关键技术、设计过程、详尽注释、秘笈心法的顺序进行了分析...

    JAVA学习资源1.0

    7.Java核心技术 卷1 基础篇 8.Netty_in_Action 9.java性能优化 10.spring源码解析 11.java 8实战 12.Docker 实战 13.java高并发编程详解 14.nginx开发手册 15.mysql高性能 16.java开发实例大全 17.Java数据结构和...

    Java Web开发实例大全(基础卷) 完整pdf扫描版[179MB]

    Java Web开发实例大全(提高卷)筛选、汇集了Java Web开发从基础知识到高级应用各个层面的大量实例及源代码,共有600个左右,每个实例及源代码按实例说明、关键技术、设计过程、详尽注释、秘笈心法的顺序进行了分析...

    公司编制优化方案整理分析,java开发相应的编制优化代码.docx

    这篇文档旨在整理和分析公司编制优化方案的相关信息。我们将收集并分析公司目前的编制情况、职位需求、人员分布等信息,并提出可行的优化方案,以提高公司的编制效率和人员配备合理性。 ## 现状分析 ### 编制情况 ...

    面向对象技术与UML课件及源代码-by 南邮-陈杨

    本书为中南大学精品教材立项项目,分为上下两篇共21章,涵盖了面向对象技术中Java开发环境配置、程序设计基础、面向对象原理以及UML的知识。本书使用的开发环境是JDK 1.6+Eclipse 3.3+Rational Rose 2003,逐步引领...

    java8集合源码分析-Notes:笔记

    SpringBoot整合篇(整合Redis、RocketMQ、定时任务等,后续补充。) 数据库、Linux(---后续补充---) 本站说明 本站目的是记录技术学习笔记,分享技术学习笔记、技术文章、优秀资源。 若您认为侵犯你的个人知识产权,...

    JAVA基于遗传算法的中药药对挖掘系统的设计与实现(源代码+论文).rar

    它包含了完整的Java代码和一篇详细的论文,旨在帮助学生和研究人员了解并实践使用遗传算法在中药药对挖掘领域的应用。遗传算法是一种模拟自然选择和遗传学机制的搜索启发式算法,非常适合解决优化和搜索问题。在这个...

    Java在游戏编程中的应用

    接着,文章详细阐述了Java游戏开发的流程,包括设计游戏需求、选择开发框架、学习编程语言和相关技术、编写游戏代码、测试和优化以及发布和运营。 文章以一个简单的Java游戏——贪吃蛇游戏为例,详细介绍了如何使用...

    java无限爬取新浪博客蜘蛛程序1.20版本 for windows界面风格

    取替了原本习惯的java桌面风格 java无限爬取新浪博客网络蜘蛛1.20版本发布 此版本需要正常安装JDK.15以上 如果需要用安装版的和我联系我发给你 包括网络测试 和数据库 统计 在原来的基础上更新 网速好的话每小时抓取...

    Android应用开发揭秘pdf高清版

    第二部分 基础篇 第3章 Android程序设计基础 3.1 Android程序框架 3.1.1 Android项目目录结构 3.1.2 Android应用解析 3.2 Android的生命周期 3.3 Android程序U设计 3.4 小结 第4章 用户界面开发 4.1 用户界面开发...

    Java经典入门教程pdf完整版

    写完Jaa代码后,机器并不认识我们写的Java代码,需要进行编译成为字节码,编译 后的文件叫做clas文件。如上图所示的 Hello, class文件。 3:类装载 Classloader 类裝载的功能是为执行程序寻找和装载所需要的类 ...

    看透springMvc源代码分析与实践

    第一篇 网站基础知识 第1章 网站架构及其演变过程2 1.1 软件的三大类型2 1.2 基础的结构并不简单3 1.3 架构演变的起点5 1.4 海量数据的解决方案5 1.4.1 缓存和页面静态化5 1.4.2 数据库优化6 1.4.3 分离...

    Visual C++实践与提高-COM和COM+篇『PDF』

    11.2.8 IUnknown优化 11.2.9 DCOM安全机制 11.3 DCOM组件的开发与部署 11.3.1 基于NT服务的DCOM服务器——例程DCOMServ 11.3.2 测试服务程序 11.3.3 DCOMCNFG实用程序 11.3.3.1 缺省属性 11.3.3.2 缺省安全性 11.3....

    leetcode分类-JavaStudy:Java学习

    Java基础 动态代理demo 实现 反射的各种基础 反射和注解的结合 反射绕过泛型产生泛型擦除 Java8 新特性(函数式接口、静态导入、Optional、Stream、Lambda、新时间类) java IO NIO Netty 简单实现 java并发知识 ...

    《Android应用开发揭秘》附带光盘代码.

     第二部分 基础篇  第3章 Android程序设计基础  3.1 Android程序框架  3.1.1 Android项目目录结构  3.1.2 Android应用解析  3.2 Android的生命周期  3.3 Android程序U设计  3.4 小结  第4章 用户界面开发 ...

    精通matlab7光盘内容分享-精通matlab7源程序.rar

    基础篇为前面的34章,主要讲述matlab的基本使用,分别为:基础入门、matlab桌面、数组及其操作、多维数组及其操作、数据类型概述和数值类型、结构体和元胞数组、字符串、关系运算和逻辑运算、程序控制流、函数、m...

Global site tag (gtag.js) - Google Analytics