第五条:避免创建不必要的对象

一般来说,最好能重用对象而不是在每次需要的时候就创建一个相同功能的新对象。重用方式既快速,又流行。如果对象是不可变的,他始终可以被重用。

反面例子:

String S = new String("dali");

该语句每次执行的时候都创建一个新的String实例,但是这些创建对象的动作全部都是不必要的。

改进后:

String s = "dali";

这个版本只用了一个String实例,而不是每次执行的时候都创建一个新的实例。而且,它可以保证,对于所有在同一台虚拟机中运行的代码,只要他们包含相同的字符串字面常量,该对象就会被重用。

除了重用不可变的对象之外,也可以重用那些已知不会被修改的可变对象。

public class Person{

     private  final Date  birthDate;

     public  Person(Date birthDate){

               this.birthDate=new Date(birthDate.getTime());

     }

     public boolean isBabyBoomer(){

             Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT+8"));

             gmtCal.set(1946,Calendar.JANUARY,1,0,0,0);

             Dateboom Start = gmtCal.getTime();

             gmtCal.set(1965,Calendar.JANUARY,1,0,0,0);

             DateboomEnd=gmtCal.getTime();

             return birthDate.compareTo(boomStart)>=0&&

                           birthDate.compareTo(boomEnd)<0;

        }

}

isBabyBoomer每次调用的时候,都会创建一个Calendar、一个TimeZone和两个Date实例,这是不必要的。

正确方式:

public class Person{

     private final Date birthDate;

     public Person(DatebirthDate){

               this.birthDate=newDate(birthDate.getTime());

      }

      private static final Date BOOM_START;

      private static final Date BOOM_END;

      static{

             Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT+8"));

             gmtCal.set(1946,Calendar.JANUARY,1,0,0,0);

             BOOM_START=gmtCal.getTime();

             gmtCal.set(1965,Calendar.JANUARY,1,0,0,0);

             BOOM_END=gmtCal.getTime();

       }

      public boolean isBabyBoomer(){

               return  birthDate.compareTo(BOOM_START)>=0&&

                      birthDate.compareTo(BOOM_END)<0;

        }

}

这种只在初始化时候创建Calendar、TimeZone和Date实例一次,而不是在每次调用isBabyBoomer的时候创建这些实例。如果isBabyBoomer方法被频繁地调用,这种方法将会显著地提高性能。

避免进行隐式装箱

自动装箱是Java5引入的一个特性,即自动将原始类型的数据转换成对应的引用类型,比如int转为Integer等。

这种特性,在编码时稍有不注意就可能创建了不必要的对象了。

反面例子:

Integer sum = 0;

for (int i = 1000; i <5000; i++) {

        sum +=i;

}

上面的代码sum+=i可以看成sum =sum+i,但是+不适用于Integer对象,首先sum进行自动拆箱操作,进行数值相加操作,最后在自动装箱转换成Integer对象。其内部实现如下:

int result = sum.intValue() + i;

Integer sum = new Integer(result);

由于这里声明的sum为Integer类型,在上面的循环中会创建将近4000个无用的Integer对象,在这个循环中,会降低程序的性能并且加重了垃圾回收的工作量。因此在我门编程时,需要注意到这一点,正确地声明 变量类型,避免因为自动装箱引起的性能问题。

谨慎选用容器

java提供了很多编辑的容器集合来组织对象。比如ArrayList,HashMap等。

容器虽然使用起来方便,但存在一些问题,就是他们会自动扩容,这其中不是创建新的对象,而是创建一个更大的容器对象。这就意味着将占用更大的内存空间。

以HashMap为例,当我们put key和value时,会检测是否需要扩容,如需要则双倍扩容。

public V put(K key, V value) {

     if (key == null)

           return putForNullKey(value);

    int hash = hash(key.hashCode());

    int i = indexFor(hash, table.length);

   for (Entry e = table[i]; e != null; e = e.next) {

       Object k;

       if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {

           V oldValue = e.value;

           e.value = value;

           e.recordAccess(this);

           return oldValue;

       }

}

modCount++;

addEntry(hash, key, value, i);

return null;

}


void addEntry(int hash, K key, V value, int bucketIndex) {

Entry e = table[bucketIndex];

        table[bucketIndex] = new Entry(hash, key, value, e);

        if (size++ >= threshold)

             resize(2 * table.length);

}

建议:预估一个较大的容量值,避免多次扩容


      不要错误地认为本条码所介绍的内容暗示着“创建对象的代价非常昂贵,我们应该要尽可能地避免创建对象”。相反,由于小对象的构造器只做很少量的显式工作,所以,小对象的创建和回收动作是非常廉价的,特别是在现代的JVM实现上更是如此。通过创建附加的对象,提升程序的清晰性、简洁性和功能性,这通常是件好事。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容