Effective Java Item5-在可以重用对象的时候避免创建对象

Item5 Avoid creating unnecessary objects

避免创建不必要的对象

 

一般情况下,最好重用功能上对等的对象,而不是创建新的对象。重用对象可以提高性能,并且样式良好。如果对象是immutable(private fields, no setter methods),那么重用起来就比较方便。

不良例子:

String name = new String(“HelloWorld”);

每次执行时,都会创建一个新的String对象。其中构造方法的参数本身就是一个对象,这样的构造方法没有必要,如果这样的语句出现在循环中,将会导致非常多的不必要的对象的创建。

修正:

String name = “HelloWorld”;

该语句创建了单一的对象。这个对象还可以被之后运行在同一个虚拟机总的其他使用相同字符串的代码重用。

package com.googlecode.javatips4u.effectivejava.unnecessary;

 

public class UnnecessaryObjectsSample {

 

      public static void main(String[] args) {

            long nanoTime = System.nanoTime();

            String name = null;

            for (int i = 0; i < 10000; i++) {

                  // DO NOT DO THIS

                  name = new String("name");

            }

            System.out.println(System.nanoTime() - nanoTime);// 2262299

            nanoTime = System.nanoTime();

            for (int i = 0; i < 10000; i++) {

                  // CHANGE TO THIS

                  name = "name";

            }

            System.out.println(System.nanoTime() - nanoTime);// 867987

            System.out.println(name);

      }

}

可以使用工厂方法来避免创建不必要的对象。

package com.googlecode.javatips4u.effectivejava.unnecessary;

 

import java.util.Calendar;

import java.util.Date;

import java.util.TimeZone;

 

public class BadMutableObjectUsage {

 

      private final Date birthDate = null;

 

      // DON'T DO THIS!

      public boolean isBabyBoomer() {

            // Unnecessary allocation of expensive object

            // Here the two Date objects are immutable.

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

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

            Date boomStart = gmtCal.getTime();

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

            Date boomEnd = gmtCal.getTime();

            return birthDate.compareTo(boomStart) >= 0

                        && birthDate.compareTo(boomEnd) < 0;

      }

}

上面例子中两个Date对象,即开始时间和结束时间是常量,所以不需要在isBabyBoomer方法中每次被调用时都进行创建,而应该作为类的静态变量进行static初始化。

package com.googlecode.javatips4u.effectivejava.unnecessary;

 

import java.util.Calendar;

import java.util.Date;

import java.util.TimeZone;

 

public class BetterMutableObjectUsage {

      private final Date birthDate = null;

      private static final Date BOOM_START_DATE;

      private static final Date BOOM_END_DATE;

      static {

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

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

            BOOM_START_DATE = gmtCal.getTime();

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

            BOOM_END_DATE = gmtCal.getTime();

      }

 

      // DON'T DO THIS!

      public boolean isBabyBoomer() {

            return birthDate.compareTo(BOOM_START_DATE) >= 0

                        && birthDate.compareTo(BOOM_END_DATE) < 0;

      }

}

同样,对于适配器(Adapter)模式而言,由于Adapter是由后台的对象支持的,所以对于同一个对象而言,没有必要为其创建多个适配器对象。例如Map接口的keySet方法返回Mapkey set

package com.googlecode.javatips4u.effectivejava.unnecessary;

 

import java.util.HashMap;

import java.util.Map;

import java.util.Set;

 

public class AdapterPattern {

      public static void main(String[] args) {

            Map<String, String> map = new HashMap<String, String>();

            map.put("key", "value");

            map.put("keys", "values");

            // all the keySet are backed by the same Map object.

            Set<String> keySet1 = map.keySet();

            map.remove("keys");

            Set<String> keySet2 = map.keySet();

            System.out.println(keySet1 == keySet2);// true

            System.out.println(keySet1.equals(keySet2));// true

      }

}

对于同一个map对象,返回的Set是一样的,改变其中的一个set,其他的set也随之而变,因为他们都是由一个后台的Map对象来支持的。

另外,自动装箱(auto-boxing)操作也会带来隐式对象的创建:

public static void main(String[] args) {

      Long sum = 0L;

      for (long i = 0; i < Integer.MAX_VALUE; i++) {

            // so many Long objects are created here.

            // coz sum is Long but not long.

            sum += i;

      }

      System.out.println(sum);

}

通过维持自定义的对象池(Object Pool)来避免创建不必要的对象是不好的,除非要创建的对象是重量级的对象。例如数据库连接。一般来讲,对象池会造成代码复杂,同时性能下降,现代的JVMGC已经高度优化。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值