`
iloveflower
  • 浏览: 79737 次
社区版块
存档分类
最新评论
  • iloveflower: 呵呵。好好学习。。。。。。。。。。。。
    java 读书
  • Eric.Yan: 看了一点,不过是电子版的……你这一说到提醒我了,还要继续学习哈 ...
    java 读书

Lazy initialization

 
阅读更多

http://www.javapractices.com/topic/TopicAction.do;jsessionid=6E104A048475638493BA555238EC17F4?Id=34

Lazy initialization is a performance optimization. It's used when data is deemed to be 'expensive' for some reason. For example: ■if the hashCode value for an object might not actually be needed by its caller, always calculating the hashCode for all instances of the object may be felt to be unnecessary.
 ■since accessing a file system or network is relatively slow, such operations should be put off until they are absolutely required.
 Lazy initialization has two objectives : ■delay an expensive operation until it's absolutely necessary 
■store the result of that expensive operation, such that you won't need to repeat it again
 
As usual, the size of any performance gain, if any, is highly dependent on the problem, and in many cases may not be significant. As with any optimization, this technique should be used only if there is a clear and significant benefit.
 
To avoid a NullPointerException, a class must self-encapsulate fields that have lazy initialization. That is, a class cannot refer directly to such fields, but must access them through a method.
 
The hashCode method of an immutable Model Object is a common candidate for lazy initialization.
 
Example 1 

In this example, there are two fields with lazy initialization - fHashCode and fAwards.
 

import java.util.*;

public final class Athlete {

  public Athlete(int aId){
    //a toy implementation:
    fId = aId;
    fName = "Roger Bannister";
    //fAwards is not set here!
  }

  //..elided

  /**
   Lazy initialization is used here; this assumes that awards
   may not always be of interest to the caller,
   and that for some reason it is particularly expensive to
   fetch the List of Awards.
  */
  public List getAwards(){
    if ( fAwards == null ) {
      //the fAwards field has not yet been populated
      //Here is a toy implementation
      List<String> awards = new ArrayList<String>();
      awards.add( "Gold Medal 2006" );
      awards.add( "Bronze Medal 1998" );
      fAwards = awards;
    }
    return fAwards;
  }

  /**
   This style applies only if the object is immutable.
   
   Another alternative is to calculate the hashCode once, when the 
   object is initially constructed (again, applies only when object is 
   immutable).
  */
  @Override public int hashCode(){
    if ( fHashCode == 0 ) {
     fHashCode = HashCodeUtil.SEED;
     fHashCode = HashCodeUtil.hash(fHashCode, fId);
     fHashCode = HashCodeUtil.hash(fHashCode, fName);
     //self-encapusulated: fAwards is not referenced directly, 
     //since it may be null:
     fHashCode = HashCodeUtil.hash(fHashCode, getAwards());
    }
    return fHashCode;
  }

  // PRIVATE //
  private int fId;
  private String fName;
  private List<String> fAwards;
  private int fHashCode;
} 
 

Example 2 

Here, the look up of the printers available to a desktop PC is treated as an expensive operation.
 

import java.util.Arrays;
import java.util.List;

import javax.print.DocFlavor;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.standard.OrientationRequested;
import javax.print.attribute.standard.Sides;

/** Printing services available to a desktop client. */
public final class Printers {

  /** Print some plain text (perhaps internally converted to PDF). */
  void printSomething(String aText, PrintService aPrinter) {
    //...elided
  }

  /** Return the list of printers that can print PDFs (double-sided, portrait).*/
  List<PrintService> listAvailablePrinters(){
    if(fAvailablePrinters == null){
      //double-sided, portrait, for PDF files.
      PrintRequestAttributeSet attrs = new HashPrintRequestAttributeSet();
      attrs.add(Sides.DUPLEX);
      attrs.add(OrientationRequested.PORTRAIT);
      //Expensive operation! This can take several seconds in some environments:
      fAvailablePrinters = Arrays.asList(
        PrintServiceLookup.lookupPrintServices(DocFlavor.INPUT_STREAM.PDF, attrs)
      );
    }
    return fAvailablePrinters;
  }
  
  // PRIVATE
  
  /**
   Looked up once, the first time it's needed, and then stored using a 
   static reference. If it was a non-static reference, then 
   the list of available printers would not be looked up just once, 
   but perhaps many times (once per 'Printers' object, and not once per 
   loaded 'Printers' class).
   
   Self-encapsulate :
   If this class's implementation needs to reference this item, it must do 
   so indirectly, by calling listAvailablePrinters().  
  */
  private static List<PrintService> fAvailablePrinters;
  
}  
 

Example 3 
Lazy initialization is particularly useful for GUIs which take a long time to construct.
 
There are several policies for GUI construction which a design may follow: 
■ always build - construct the window many times, whenever it is demanded, and do not cache the result.
■ first-request build - construct the window once, when first requested. Cache the result for any further requests, should they occur.
■ background build - construct the window once, in a low priority worker thread, when the system is initialized. Cache the result for any requests, should they occur.
 Here is an example of the first-request style, in which the fEditor field has lazy initialization (see the actionPerformed method).
 
package hirondelle.stocks.preferences;

import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.util.logging.*;

import hirondelle.stocks.util.Args;
import hirondelle.stocks.util.ui.StandardEditor;
import hirondelle.stocks.util.ui.UiUtil;
import hirondelle.stocks.preferences.PreferencesEditor;
import hirondelle.stocks.util.Util;

/**
* Present dialog to allow update of user preferences.
*
* <P>Related preferences are grouped together and placed in 
* a single pane of a <tt>JTabbedPane</tt>, which corresponds to an 
* implementation of {@link PreferencesEditor}. Values are pre-populated with 
* current values for preferences.
*
*<P>Most preferences have default values. If so, a  
* <tt>Restore Defaults</tt> button is provided for that set of related 
* preferences.
*
*<P>Preferences are not changed until the <tt>OK</tt> button is pressed. 
* Exception: the logging preferences take effect immediately, without the need 
* for hitting <tt>OK</tt>.
*/
public final class EditUserPreferencesAction extends AbstractAction {

  /**
  * Constructor.
  *  
  * @param aFrame parent window to which this dialog is attached.
  * @param aPrefEditors contains implementations of {@link PreferencesEditor}, 
  * each of which is placed in a pane of a <tt>JTabbedPane</tt>.
  */
  public EditUserPreferencesAction (JFrame aFrame, List<PreferencesEditor> aPrefEditors) {
    super("Preferences...", UiUtil.getEmptyIcon()); 
    Args.checkForNull(aFrame);
    Args.checkForNull(aPrefEditors);
    fFrame = aFrame;
    putValue(SHORT_DESCRIPTION, "Update user preferences");
    putValue(LONG_DESCRIPTION, "Allows user input of preferences.");
    putValue(MNEMONIC_KEY, new Integer(KeyEvent.VK_P) );    
    fPrefEditors = aPrefEditors;
  }

  /** Display the user preferences dialog.  */
  public void actionPerformed(ActionEvent event) {
    fLogger.info("Showing user preferences dialog.");
    //lazy construction: fEditor is created only once, when this action 
    //is explicitly invoked
    if ( fEditor == null ) {
      fEditor = new Editor("Edit Preferences", fFrame);
    }
    fEditor.showDialog();
  }
  
  // PRIVATE //
  private JFrame fFrame;
  private java.util.List<PreferencesEditor> fPrefEditors;
  private static final Logger fLogger = Util.getLogger(EditUserPreferencesAction.class);  
  
  /**
  * Specifying this as a field allows for "lazy" creation and use of the GUI, which is 
  * of particular importance for a preferences dialog, since they are usually heavyweight, 
  * and have a large number of components.
  */
  private Editor fEditor;
  
  /**
  * Return GUI for editing all preferences, pre-populated with current 
  * values.
  */
  private JComponent getPrefEditors(){
    JTabbedPane content = new JTabbedPane();
    content.setTabPlacement(JTabbedPane.LEFT);
    int idx = 0;
    for(PreferencesEditor prefEditor: fPrefEditors) {
      JComponent editorGui = prefEditor.getUI();
      editorGui.setBorder(UiUtil.getStandardBorder());
      content.addTab(prefEditor.getTitle() , editorGui);
      content.setMnemonicAt(idx, prefEditor.getMnemonic());
      ++idx;
    }
    return content;
  }
  
  /** Called only when the user hits the OK button.  */
  private void saveSettings(){
    fLogger.fine("User selected OK. Updating table preferences.");
    for(PreferencesEditor prefEditor: fPrefEditors) {
      prefEditor.savePreferences();
    }
  }
  
  /**
  * An example of a nested class which is nested because it is attached only 
  * to the enclosing class, and it cannot act as superclass since multiple 
  * inheritance of implementation is not possible. 
  * 
  * The implementation of this nested class is kept short by calling methods 
  * of the enclosing class.
  */
  private final class Editor extends StandardEditor { 
    
    Editor(String aTitle, JFrame aParent){
      super(aTitle, aParent, StandardEditor.CloseAction.HIDE);
    }

    public JComponent getEditorUI () {
      JPanel content = new JPanel();
      content.setLayout( new BoxLayout(content, BoxLayout.Y_AXIS) );
      content.add( getPrefEditors() );
      //content.setMinimumSize(new Dimension(300,300) );
      return content;
    }
    
    public void okAction() {
      saveSettings();
      dispose();
    }
  }  
}
分享到:
评论

相关推荐

    Hibernate延时加载与lazy机制.doc

    Hibernate的延迟加载(Lazy Loading)和懒加载机制(Lazy Initialization)是优化ORM框架性能的重要策略。这个机制的主要目的是提高程序的效率,减少不必要的数据库交互,只在真正需要数据时才去加载它们。以下是对...

    Lazy.Object.Initialize

    在.NET框架中,`Lazy&lt;T&gt;`是一个非常有用的类,它实现了延迟初始化(Lazy Initialization)模式。这个模式的主要目的是推迟对象的创建,直到第一次真正需要它时才进行实例化,这样可以提高程序性能,特别是对于那些...

    System.Lazy 实例的延迟初始化值

    在.NET框架中,`System.Lazy&lt;T&gt;`是一个强大的工具,用于实现延迟初始化(Lazy Initialization)。延迟初始化是一种设计模式,它推迟对象的创建或资源的加载,直到第一次真正需要它们时。这种方式可以提高程序的性能...

    深入剖析Java中的双检锁模式:实现、陷阱与最佳实践

    在Java并发编程中,双检锁(Double-Checked Locking)是一种用于减少同步开销的优化技术,尤其适用于懒加载(lazy initialization)的场景。本文将详细探讨双检锁的工作原理、潜在问题以及如何安全地实现它。 双检锁...

    Spring Boot 全局懒加载机制.docx

    然而,有时我们希望某些bean在实际需要时才进行初始化,这就是所谓的“懒加载”(Lazy Initialization)。Spring Boot 2.2及更高版本引入了一个全局懒加载机制,允许用户通过配置开启整个应用的bean懒加载,以优化...

    java-thread-safe-singleton-pattern.rar_starvation

    本主题探讨的是线程安全的单例模式实现,特别是饥饿模式(Starvation)和延迟加载(Lazy Initialization)两种策略。 首先,让我们理解什么是线程安全。在多线程环境下,如果一个类的实例可以被多个线程同时访问,...

    c#单例模式示例

    在C#中,单例模式可以通过多种方式实现,如Eager Initialization(急切初始化)、Lazy Initialization(懒惰初始化)以及线程安全的懒惰加载等。本文将重点介绍C#中两种不同的单例模式实现方法:基于嵌套类的完全...

    单件模式demo

    1. **经典懒汉式(Lazy Initialization)**: 这种方式是在第一次调用GetInstance方法时才创建实例。但是这种方式在多线程环境下可能存在问题,因为多个线程可能会同时创建单例对象。 ```csharp public class ...

    java 单工厂模式

    在Java中,实现单例模式通常使用懒汉式(lazy initialization)或饿汉式(eager initialization)。懒汉式是在第一次调用getInstance()方法时才创建实例,而饿汉式则是在类加载时就创建实例。在上述代码示例中,使用...

    基于C#的设计模式中的单件模式

    2. 懒汉式(Lazy Initialization) 懒汉式是在首次调用时才进行实例化,因此也被称为延迟初始化。为了保证线程安全,C#提供了`System.Lazy&lt;T&gt;`类,可以实现线程安全的懒汉式单例。 ```csharp public sealed class ...

    22种开发模式

    Lazy initialization holder class 模式是指使用类级的内部类来实现延迟加载,下面是代码示例: ```java public class Singleton3 { / * 类级的内部类,也就是静态的成员式内部类,该内部类的实例与外部类的实例 ...

    C#面向对象设计模式纵横谈(2)Singleton 单件(创建型模式)

    1. **懒汉式(Lazy Initialization)**:这是最常见的实现方式,延迟实例化直到首次被请求时。这种方式既实现了单例,又避免了不必要的初始化。例如: ```csharp public sealed class Singleton { private static ...

    白话讲解创建型设计模式:单例原型构建

    懒汉式(Lazy Initialization)则是在第一次使用时才创建实例,但原始的实现方式不线程安全。为了解决这个问题,我们可以使用同步方法(Synchronized Singleton),但这会降低并发性能。双重检查锁定(Double-Check ...

    详解Spring 中如何控制2个bean中的初始化顺序

    这种方法的优点是可以做到 lazy initialization,但是如果类似逻辑很多的话,代码中到处充斥着类似代码,不优雅。 方案二:使用 DependsOn Spring 中的 DependsOn 注解可以保证被依赖的 bean 先于当前 bean 被容器...

    Spring2.5学习笔记

    - **Default Lazy Initialization**:若希望对所有 Bean 都应用懒加载,则可以在 `&lt;beans&gt;` 根节点中设置 `default-lazy-init="true"`。 - **初始化和销毁方法**:可以指定初始化和销毁方法来管理 Bean 的生命周期...

    C++设计模式-单实例

    2. **懒汉式**(Lazy Initialization): - 懒汉式是在第一次真正需要单例时才进行实例化,实现了按需创建,节约了内存空间。 - 传统的懒汉式实现可能存在线程安全问题,需要在多线程环境中进行同步控制,如使用...

    Java标准版的EJB Persistence(二)

    然而,当尝试通过Address对象获取其关联的Person集合时,会出现懒加载(lazy initialization)问题。默认情况下,JPA只会延迟加载集合,直到我们实际访问该字段时才去数据库获取数据。为了解决这个问题,我们可以将@...

    Sprig学习笔记—适用刚接触者

    4. **延迟加载(Lazy Initialization)**:通过`lazy-init`属性,可以控制Bean是否延迟初始化。如果设置为`true`,Bean将在第一次请求时才实例化。全局设置`default-lazy-init`可以让所有Bean默认延迟加载。 5. **...

    spring-learn.zip

    当检测到循环依赖时,Spring会尝试通过预初始化(Lazy Initialization)和早周期引用(Early Reference)的方式来打破循环。 1. 预初始化:默认情况下,Spring的bean默认为懒加载(Lazy),只有在被请求时才会实例...

    jdbc连接工具类 单例连接模式,进度1

    2. 懒汉式(Lazy Initialization):首次使用时才创建单例,线程不安全,需要配合同步机制。 3. 双重检查锁定(Double-Check Locking):兼顾延迟初始化和线程安全,是推荐的实现方式。 4. 静态内部类:利用类加载...

Global site tag (gtag.js) - Google Analytics