`
hy2012_campus
  • 浏览: 29112 次
  • 性别: Icon_minigender_1
  • 来自: 河南
社区版块
存档分类
最新评论

java代码优化

    博客分类:
  • java
阅读更多

来源于:http://thecodesample.com/

本文给出几个提升Java性能的基本方法:

不要在循环条件中计算

如果在循环 (如for循环、while循环)条件中计算,则循环一遍就要计算一次,这会降低系统的效率,如:

//每次循环都要计算 count *2
while(i < count *2) {
    //Do something ...
}
应该替换为:
//只计算一遍
int total = count *2
while(i <total) {
    //Do something ...
}
再如:
for (int i=0; i<size()*2; i++) {
    //Do something
}
应该改成:
for (int i=0, stop=size()*2; i<stop; i++) {
    //Do something
}

 不要将相同的子表达式计算多次

if (birds.elementAt(i).isGrower()) ...
if (birds.elementAt(i).isPullet()) ...
将相同的子表达式提取为一个变量,如:
Bird bird = birds.elementAt(i);
if (bird.isGrower()) ...
if (bird.isPullet()) ...

 

减少数组访问次数,每次数组访问都需要检查一下索引,所以减少数组访问的次数是值得的。
double[] rowsum = new double[n];
for (int i = 0; i < n; i++)
    for (int j = 0; j < m; j++)
        rowsum[i] += arr[i][j];
改成如下形式:
double[] rowsum = new double[n];
for (int i = 0; i < n; i++) {
    double[] arri = arr[i];
    double sum = 0.0;
    for (int j = 0; j < m; j++)
        sum += arri[j];
    rowsum[i] = sum;
}

 尽可能把变量、方法声明为 final static 类型

如下例子用于返回给定年份给定月份所具有的天数。

public static int monthdays(int y, int m) {
    int[] monthlengths = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    
    return m == 2 && leapyear(y) ? 29 : monthlengths[m-1];
}

 上述方法每次调用都会重新生成一个monthlengths 数组,但必要要主要的是:数组不会改变,属于不变数组。在这种情况下,

把它声明为 final static 更加合适,在类加载后就生成该数组,每次方法调用则不再重新生成数组对象了,这有助于提高系统性能。

应该改成:
private final static int[] monthlengths = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
public static int monthdays(int y, int m) {
    return m == 2 && leapyear(y) ? 29 : monthlengths[m-1];
}
稍微复杂一些的初始化可以使用静态初始化块static {… }来做,如:
private final static double[] logFac = new double[100];
static {
    double logRes = 0.0;
    for (int i=1, stop=logFac.length; i<stop; i++)
        logFac[i] = logRes += Math.log(i);
}
 
public static double logBinom(int n, int k) {
    return logFac[n] - logFac[n-k] - logFac[k];
}

 缩小变量的作用范围

关于变量,能定义在方法内的就定义在方法内,能定义在一个循环体内的就定义在循环体内,能放置在一个try…catch块内的就放置在该块内,

其目的是加快GC的回收。

 

字符串频繁”+”操作使用StringBuilder或者StringBuffer

 

虽然String的联接操作(“+”)已经做了很多优化,但大量的追加操作上StringBuilder或者StringBuffer还是比”+”的性能好很多。

String s = "";
for (int i=0; i<n; i++) {
    s += "#" + i;
}
应该改成:
StringBuilder sbuf = new StringBuilder();
for (int i=0; i<n; i++) {
    sbuf.append("#").append(i);
}
String s = sbuf.toString();
此外,
String s = "(" + x + ", " + y + ")";
它将自动会编译为StringBuilder.append(…)。

 覆写Exception的fillInStackTrace方法

fillInStackTrace方法是用来记录异常时的栈信息的,这是非常耗时的动作,如果在开发时不需要关注栈信息,则可以覆盖之,

如下覆盖fillInStackTrace的自定义异常会使性能提升10倍以上:

class MyException extends Exception {
   public Throwable fillInStackTrace() {
      return this;
   }
}

 延迟初始化

当你不知道一个对象是否需要的时候,可以选择延迟初始化:直到需要的时候才初始化,但只分配一次。

public class Car {
    private Button button = new JButton();
    public Car() {
        ... initialize button ...
    }
    public final JButton getButton() {
        return button;
    }
}
可以改为:
public class Car {
    private Button button = null;
 
    public Car() { ... }
    public final JButton getButton() {
        if (button == null) { // button not yet created, so create it
            button = new JButton();
            ... initialize button ...
        }
        return button;
    }
}

 不要重复创建对象

比如,一个商品相关信息的更新,为了搜索,需要为其创建索引。

针对单个商品建立的索引如下:

public void index(Product product) {
    if (product != null) {
        FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager);
        fullTextEntityManager.index(product);
    }
}
针对多个商品建立索引,可能会写出如下的代码,写一个for循环,直接调用单个商品索引建立的方法。
public void indexAll(List<Product> products) {
    if (products != null) {
        for (Product product : products) {
            index(product);
        }
    }
}
这个方法比较直观,但是为每一个Product创建索引的时候,都会新创建一个FullTextEntityManager对象。其实我们只需要创建一次,代码如下:
public void indexAll(List<Product> products) {
    if (products != null) {
        FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager);
        for (Product product : products) {
            fullTextEntityManager.index(product);
        }
    }
}
使用Collections.emptyXXX方法代替创建空的ArrayList,HashSet等

下面给出一个获取一个指定分类以及其所有父类的规格的方法
public Set<Specification> getAllSpecifications(ProductCategory productCategory) {
    Set<Specification> specifications = new HashSet<Specification>();
    if (null != productCategory) {
        specifications.addAll(productCategory.getSpecifications());
        specifications.addAll(productCategory.getParentSpecifications());
    }
    return specifications;
}
该方法中,不管productCategory是否为空,都会新建一个空的Set集合,而每次创建的空Set也会是不同的对象。我们可以先判断商品分类是否为空
,如果是空,则调用Collections的emptySet()方法,该方法将返回一个常量的空集,并不需要重新创建新的空集对象。

 

代码如下:
public Set<Specification> getAllSpecifications(ProductCategory productCategory) {
    if(productCategory == null){
        return Collections.<Specification>emptySet();
    }
    Set<Specification> specifications = new HashSet<Specification>();
    specifications.addAll(productCategory.getSpecifications());
    specifications.addAll(productCategory.getParentSpecifications());
    return specifications;
}
去掉重复代码

下面的例子是根据一个指定分类,获取其子分类的方法, 分类结果以Map的形式返回,key为分类id,value为分类名称,这个主要用
于前台Ajax去构建分类的树形结构。如果指定的分类为null,则获取根分类。
public Map<Long, String> getSubCategoryTree(Long parentId) {
    Map<Long, String> categoryOptions = new HashMap<Long, String>();
    ProductCategory productCategory = productCategoryService.find(parentId);
    if (null == productCategory) {
        for (ProductCategory pc : productCategoryService.findRoots()) {
            categoryOptions.put(pc.getId(), pc.getName());
        }
    } else {
        for (ProductCategory pc : productCategory.getChildren()) {
            categoryOptions.put(pc.getId(), pc.getName());
        }
    }
    return categoryOptions;
}
在这个方法中,if-else语句中除了获取的集合 productCategoryService.findRoots()和 productCategory.getChildren()不同外,其余都是一样的。
我们完全可以将这个集合提取出来,代码块将不再包含if-else块,同时for循环也只需要一个。

帮助
public Map<Long, String> getSubCategoryTree(Long parentId) {
    Map<Long, String> categoryOptions = new HashMap<Long, String>();
    ProductCategory productCategory = productCategoryService.find(parentId);
    Collection<ProductCategory> productCategories = (productCategory == null) ? productCategoryService
            .findRoots() : productCategory.getChildren();
    for (ProductCategory pc : productCategories) {
        categoryOptions.put(pc.getId(), pc.getName());
    }
    return categoryOptions;
}

 

去掉不必要的else块
private int getAttributeValueId(String value) {
    if (StringUtils.isEmpty(value)) {
        return -1;
    } else {
        String[] values = value.split(ATTRIBUTE_ID_SEPARATOR);
        String id = values[values.length - 1];
        return Integer.parseInt(id);
    }
}
可以改成
private int getAttributeValueId(String value) {
    if (StringUtils.isEmpty(value)) {
        return -1;
    }
    String[] values = value.split(ATTRIBUTE_ID_SEPARATOR);
    String id = values[values.length - 1];
    return Integer.parseInt(id);
 
}

 在不需要再用时关闭连接资源

下面是一个简单的查询数据库的代码,执行完查询操作之后,判断连接资源是否为null,如不为null,则调用相应的close()方法关闭资源。

Statement stmt = null;
ResultSet rs = null;
Connection conn = getConnection();
try{
    stmt = conn.createStatement();
    rs = stmt.executeQuery(sqlQuery);
    progressResult(rs);
}catch(SQLException e){
    //forward to handler
}finally {
    if(rs !=null){
        rs.close();
    }
    if(stmt != null){
        stmt.close();
    }
    if(conn !=null){
        conn.close();
    }
}
在这个关闭的过程中,存在着风险,比如rs在调用close()方法时发生异常,则stmt和conn将不会关闭。

 为了能够使资源都得到释放,应改为:

Statement stmt = null;
ResultSet rs = null;
Connection conn = getConnection();
try{
    stmt = conn.createStatement();
    rs = stmt.executeQuery(sqlQuery);
    progressResult(rs);
}catch(SQLException e){
    //forward to handler
}finally {
     
    try{
        if(rs !=null){
            rs.close();
        }
    }catch(SQLException e){
        //forward to handler
    }finally{
        try{
            if(stmt !=null){
                stmt.close();
            }
        }catch(SQLException e){
            //forward to handler
        }finally{
            try{
                if(conn !=null){
                    conn.close();
                }
            }catch(SQLException e){
                //forward to handler
            }
        }
    }
 
}
如果使用的是JDK1.7后的版本, 也可以使用Java SE 7中支持的使用try-with-resource的方式。
try(   
	Connection conn = getConnection(); 
	Statement stmt = conn.createStatement();
	ResultSet rs = stmt.executeQuery(sqlQuery)){
    progressResult(rs);
}catch(SQLException e){
    //forward to handler
}

 

分享到:
评论

相关推荐

    JAVA代码优化工具

    JAVA代码优化工具,

    JAVA代码优化.txt

    JAVA代码优化 JAVA代码优化 JAVA代码优化 JAVA代码优化 JAVA代码优化

    Java代码优化....................

    java代码优化 个人感觉这写的不错. 值得学习!

    java代码优化简介

    优化通常包含两方面的内容:减小代码的体积,提高代码的运行效率。本文讨论的主要是如何提高代码的效率。在Java程序中,性能问题的大部分原因并不在于Java语言,而是在于程序本身。养成好的代码编写习惯非常重要,...

    Java 代码优化常见注意点

    Java 代码优化常见注意点 别人在blog里总结出来的 拿来分享给大家[免分]

    JAVA代码优化实用策略

    非常实用的java代码优化策略详解,从变量声明、初始化、字符串链接、异常处理、IO、数组等各个方面进行优化,非常有参考价值。

    44条Java代码优化建议

    44条Java代码优化建议,值得阅读一遍、并实践; 44条Java代码优化建议,值得阅读一遍、并实践

    java代码优化编程

    优化通常包含两方面的内容:减小代码的体积,提高代码的运行效率。 本文讨论的主要是如何提高代码的效率。 在 Java程序中,性能问题的大部分原因并不在于Java语言,而是在于程序本身。养成好的代码编写习惯非常重要...

    Java代码优化细节总结

    代码优化,一个很重要的课题。可能有些人觉得没用,一些细小的地方有什么好修改的,改与不改对于代码的运行效率有什么影响呢?这个问题我是这么考虑的,像大海里面的鲸鱼一样,它吃一条小虾米有用吗?没用,但是,吃...

    java代码优化大全

    可供程序利用的资源(内存、CPU时间、网络带宽等)是有限的,优化的目的就是让程序用尽可能少的资源完成预定...优化通常包含两方面的内容:减小代码的体积,提高代码的运行效率。本文讨论的主要是如何提高代码的效率。

    29个要点帮你完成java代码优化.pdf

    29个要点帮你完成java代码优化

    java代码优化笔记

    java代码开发代码优化整理笔记,仅供大家学习交流,如有侵权请尽快联系小编,如有不足,可发表评论,谢谢

    java代码优化.doc

    java代码优化.doc

    JAVA代码优化.pdf

    JAVA代码优化.pdf

    29个要点帮你完成java代码优化

    通过java代码规范来优化程序,优化内存使用情况,防止内存泄露 可供程序利用的资源(内存、CPU时间、网络带宽等)是有限的,优化的目的就是让程序用尽可能少的资源完成预定的任务。优化通常包含两方面的内容:减小...

    java代码优化编程共11页.pdf.zip

    java代码优化编程共11页.pdf.zip

Global site tag (gtag.js) - Google Analytics