Java企业教程系列

用Java 8实现懒初始化

  单例经常使用懒初始化,而且有时如果一个对象非常大且重量,那么其内部字段可以使用懒初始化的赋值方式。

  通常getter方法内有一段代码是用来检查当前被获取的对象是否已经初始化,如果没有,那么就立即进行初始化,将初始化值赋予字段对象,一旦对象已经被初始化,这种检查就没有意义,是一次性的,它只会减慢方法的执行,特别是如果使用同步锁synchronized,下面我们看看如果去除这段只使用一次的代检查码,如下面案例:

Class A{
  private B b;
  public B getB(){
    if (this.b == null)
      this.b = new B(); //只使用一次的检查代码
    return this.b
  }
}

  我们可以使用Java 8的函数编程方式来实现,其基本想法如下:

  • 使用Supplier类型替代懒初始化字段
  • 这个Supplier初始对象 (但是还不返回这个对象)
  • 然后设置字段到新的Supplier,这个Supplier返回已经被初始化的对象
  • 返回实例

  看看下面的代码:

public class Holder

{

   private Supplier heavy = () -> createAndCacheHeavy();

 

   public Heavy getHeavy()

   {

      return heavy.get();

   }

 

   private synchronized Heavy createAndCacheHeavy()

   {

      class HeavyFactory implements Supplier

      {

         private final Heavy heavyInstance = new Heavy();

 

         public Heavy get()

         {

            return heavyInstance;

         }

      }

    

      if(!HeavyFactory.class.isInstance(heavy))

      {

         heavy = new HeavyFactory();

      }

 

      return heavy.get();

   }

}

上面代码中可以正常实现懒初始化,但是createAndCacheHeavy 代码有点比较复杂。做些修改如下:

private Heavy createAndCacheHeavy()

{

   Heavy instance = new Heavy();

   heavy = () -> instance;

   return instance;

}

这比之前更加简单,为了使这个代码线程安全,需要同步getInstance()方法。

为了每次初始化时不必要建立createAndCacheHeavy这个类,我们可以做一个模板用来重用,这样只要如下调用即可:

Supplier<Heavy> heavy = LazilyInstantiate.using(() -> new Heavy());

让我们看看你这个LazilyInstantiate类模板做了些什么:

public class LazilyInstantiate implements Supplier

{

   public static  LazilyInstantiate using(Supplier supplier)

   {

      return new LazilyInstantiate<>(supplier);

   }

    

   public synchronized T get()

   {

      return current.get();

   }

    

   private LazilyInstantiate(Supplier supplier)

   {

      this.supplier = supplier;

      this.current = () -> swapper();

   }

    

   private final Supplier supplier;

   private Supplier current;

    

   private T swapper()

   {

      T obj = supplier.get();

      current = () -> obj;

      return obj;

   }

}

更详细的源码库见:Github

单例模式