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