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();
}
}
}
### 扣子智能体平台功能与使用说明 #### 平台概述 扣子Coze)是由字节跳动推出的一款面向终端用户的智能体开发平台[^3]。该平台支持用户通过零代码或低代码方式快速构建基于人工智能大模型的各种智能体应用,并能够将其部署至其他网站或者通过 API 集成到现有的系统中。 #### 快速搭建智能体 无论是具备还是缺乏编程基础的用户,都能够借助扣子平台迅速创建一个 AI 智能体。例如,可以参照一篇教程中的实例来学习如何打造一个解决日常生活问题的小助手[^1]。这不仅降低了技术门槛,还使得更多的人有机会参与到智能化工具的设计过程中去。 #### 插件系统的利用 为了进一步增强所建智能体的能力,在其技能配置环节可加入不同类型的插件。一旦添加成功,则可以在编写提示语句的时候直接调用这些插件,亦或是融入自动化流程里实现更复杂操作逻辑的目的[^2]。这种灵活运用外部资源的方法极大地拓宽了单个智能体所能覆盖的应用场景范围。 ```python # 示例:假设我们有一个简单的 Python 脚本用于模拟调用某个插件功能 def call_plugin(plugin_name, parameters): result = f"Plugin {plugin_name} called with params: {parameters}" return result example_call = call_plugin("weather", {"location": "Beijing"}) print(example_call) ``` 上述代码片段仅作为概念展示之用,实际情况下具体实现会依据官方文档指导完成。 #### 总结 综上所述,扣子智能体平台提供了便捷高效的途径让用户无需深厚编码背景即可打造出满足特定需求的AI解决方案;同时它开放性强允许接入第三方服务从而提升整体性能表现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值