Lazy loading in Java
Lazy loading is the idea of waiting to load an object until you need it. In other words, it is the practice of postponing class instantiation until it is necessary. When the cost of constructing an object is high, or the item is rarely used by the program, lazy loading is crucial. A method for increasing program efficiency is lazy loading. We will go into more detail about lazy loading in this section.
Initializing a class only when it is truly required is known as "lazy loading," which is just a fancy word for the procedure.
In order to maintain ease of use and boost efficiency, lazy loading is a software design style where object initialization only takes place when it is truly required and not before.
When the cost of creating an item is very expensive, and its use is quite uncommon, lazy loading is crucial. Therefore, this situation justifies the implementation of lazy loading. Loading objects and data only when necessary is the core concept of lazy loading.
Assume, for instance, that you are developing an application with a ContctList object that holds a list of the firm's employees and an organization object that represents the company. A corporation may have thousands of employees. It could take a long time to load the ContctList object, the Company object, and the ContctList object's list of all the company's employees from the database. Even when you don't need the personnel list, you often have to wait until the company's information is loaded into the RAM.
Employing the Lazy Loading Design Pattern, it is possible to delay loading employee objects until they are needed, which can save both time and memory.
Implementation of Lazy loading:
Virtual Proxy:
Virtual Proxy is a memory-saving technique that encourages delaying the creation of objects. Take note of the program below.
LazyLoadExample.java
// demonstrating Lazy Loading in Java (virtual Proxy)
// import statements
import java.io.*;
import java.util.ArrayList;
import java.util.List;
// declaring the interfaces
interface IcontctList
{
public List<Employees> getEmploList ();
}
class Company
{
// fields or variables or attributes of the compny class
String cNam;
String cAdd;
String cContctNo;
IcontctList contList;
// constructor helpful in initializing the class variables and fields
public Company (String cNam, String cAdd, String cContctNo, IcontctList contList)
{
this.cNam = cNam;
this.cAdd = cAdd;
this.cContctNo = cContctNo;
this.contList = contList;
}
// a get method to retrieve the name of compny
public String getCompanyName ()
{
return this.cNam;
}
// a get method to retrieve the address of compny
public String getCompanyAddress ()
{
return this.cAdd;
}
public String getCompanyContactNo ()
{
return this.cContctNo;
}
// a get method to get the contct list
public IcontctList getcontList ()
{
return this.contList;
}
}
class ContactList implements IcontctList
{
// retrieving the list
@Override
public List<Employees> getEmploList()
{
return getEmpList();
}
private static List<Employees> getEmpList ()
{
List<Employees> empList = new ArrayList<Employees> (5);
// adding employees to list
empList.add (new Employees ("Mohan", 3452.67, "SDE3"));
empList.add (new Employees ("Ajay", 22745, "ASE"));
empList.add (new Employees ("Nani", 3266.17, "G4"));
empList.add (new Employees ("Virat", 4795.34, "SDE1"));
empList.add (new Employees ("Akhila", 2657.87, "SDE"));
return empList;
}
}
class ContactListProxy implements IcontctList
{
private IcontctList contList;
@Override
public List<Employees> getEmploList ()
{
if (contList == null)
{
System.out.println ("printing the list of employees ... \n");
contList = new ContactList ();
}
return contList.getEmploList ();
}
}
class Employees
{
// Attributes of the employee's class
private String empNam;
private double empSal;
private String empDes;
// constructor initializing the class attributes/fields
public Employees (String empNam, double empSal, String empDes)
{
this.empNam = empNam;
this.empSal = empSal;
this.empDes = empDes;
}
// a get method to get employee name
public String getempNam ()
{
return empNam;
}
// a get method to figure out the employee salary
public double getempSal ()
{
return empSal;
}
// a get method to get the designation
public String getempDes ()
{
return empDes;
}
@Override
public String toString ()
{
String res = "employee Name: " + empNam + ", empDesignation : " + empDes + ", Employee Salary : " + empSal;
return res;
}
}
// main class
public class LazyLoadExample
{
public static void main (String [] args)
{
// ContactListProxy class
IcontctList contListObj = new ContactListProxy ();
// instant of the compny class
Company compObj = new Company ("JTP", "India", "+91-011-59502347", contListObj);
System.out.println ("Compny Name: " + compObj.getCompanyName ());
System.out.println ("Compny Address: " + compObj.getCompanyAddress ());
System.out.println ("Compny Contact No.: " + compObj.getCompanyContactNo () + "\n");
System.out.println ("Requesting for the contact list ...");
contListObj = compObj.getcontList ();
List<Employees> employeeList = contListObj.getEmploList ();
for (Employees emp : employeeList)
{
System.out.println (emp);
}
}
}
Output:

We have created an instance of the ContactListProxy class in the code. The list of employees has not yet been made. This is because the list of employees is not currently necessary. When the list of workers is required, the function getEmployeeList () is called, and the list is generated at the same time, illustrating that the production of the list of employees is postponed until required.
Lazy initialization:
The Lazy Initialization technique shows how to check a class field's value when its use is necessary. If the value of the class field is null, the field is modified with the correct value before being returned. The same is demonstrated by the example below.
LazyLoadingExample.java
import java.util.Map;
import java.util.HashMap;
import java.util.Map.Entry;
enum CarTypes
{
Hyundai ,
suzuki,
Ferrari
}
class CarModel
{
// a class field that keeps CarTypes as the key and its object as the value
private static Map<CarTypes, CarModel> typeMap = new HashMap<>();
// private(access specifier) constructor of the class CarModel
private CarModel (CarTypes type)
{
}
public static CarModel getCarByTypeName (CarTypes type)
{
CarModel carObj;
// load the type in the map typeMap if type is not present
if (!typeMap.containsKey(type))
{
carObj = new CarModel (type);
typeMap.put (type, carObj);
}
else
{
// if present currently
carObj = typeMap.get (type);
}
return carObj;
}
public static void displayAll ()
{
// calculation of the size of the map
int size = typeMap.size ();
// displaying when map isn’t empty
if (size > 0)
{
System.out.println (" instances created = " + size);
// looping through each entry of the typeMap, displaying them
for (Entry<CarTypes, CarModel> entry : typesMap.entrySet())
{
String car = entry.getKey().toString();
car = Character.toUpperCase (car.charAt (0)) + car.substring (1);
System.out.println (car);
}
System.out.println ();
}
}
}
public class LazyLoadExample
{
public static void main (String args [])
{
CarModel.getCarByTypeName (CarTypes.suzuki);
CarModel.displayAll ();
CarModel.getCarByTypeName (CarTypes.Ferrari);
CarModel.displayAll ();
CarModel.getCarByTypeName (CarTypes.Hyundai );
CarModel.displayAll ();
}
}
Output:

The lazy initialization of the map field is done in the code by the getCarByTypeName () method. It begins by determining whether the requested car type is present or not. If it isn't already there, the relevant car type is created and then loaded onto the map. Take note that the Cars class's function Object () {[native code]} has been purposefully made secret. The private function Object () {[native code]} makes sure that an object of the class Cars can never be created. A suitable instance of the class Cars is only produced or loaded when necessary because an instance of the class Cars is only created when the method getCarByTypeName () is used.