When should a static intializer be used?
Taken from the documentation you linked above:
The instance initialization code in a class is executed every time an object is instantiated from that class. These code blocks run before the constructor.
If you do not want to write your own constructor for a class, you can use an instance initialization code block to initialize instance variables. However, most of the time you should either give the variable a default value or use the body of a constructor to do initialization and not use instance initialization code.
Similar to other static code, a static initialization code block is only initialized once on the first use of the class.
A perfect use case for this would be a utility class. Let's take a look at some code:
public class DiscountUtility{
public static final Double DISCOUNT;
static{
Custom_Setting_Config__c settings = Custom_Setting_Config__c.getInstance();
DISCOUNT = settings.Discount__c;
}
public static Double applyDiscount(Double value) {
return value - DISCOUNT;
}
}
You could then use this like:
public class StoreCheckoutController{
public Double cartAmount{get;set;}
public void finalizeCheckout(){
if(condition){
DiscountUtility.applyDiscount(cartAmount);
}
}
}
Notice how I am using a static method on the utility class and I never initialize the DiscountUtility class. Without initializing it, I would never be able to set the custom setting value (assuming the discount can change from environment to environment). It does have a limited use case. Normally, you would be able to just use a constructor. If you were creating an actual instance of a class, you could simply write the code like:
public class DiscountUtility{
public static final Double DISCOUNT;
public DiscountUtility(){
Custom_Setting_Config__c settings = Custom_Setting_Config__c.getInstance();
DISCOUNT = settings.Discount__c;
}
public Double applyDiscount(Double value) {
return value - DISCOUNT;
}
}
Then all you would need to do to populate that amount be would:
public class StoreCheckoutController{
public Double cartAmount{get;set;}
public void finalizeCheckout(){
if(condition){
DiscountUtility util = new DiscountUtility();
util.applyDiscount(cartAmount);
}
}
}
The difference is the first situation requires no instance of the class to even be created and thus is much more efficient for a static utility class.
As @jkraybill pointed out, this type of scenario may not be the most efficient for the scenario I described above. From the documentation:
Static variables are only static within the scope of the request. They are not static across the server, or across the entire organization.
as well as from the documentation on Custom Settings:
Custom settings are similar to custom objects and enable application developers to create custom sets of data, as well as create and associate custom data for an organization, profile, or specific user. All custom settings data is exposed in the application cache, which enables efficient access without the cost of repeated queries to the database. This data can then be used by formula fields, validation rules, Apex, and the SOAP API.
For instance, say your utility class looked like:
public class DiscountUtility{
public static Double discount{
get{
if(discount == null){
Custom_Setting_Config__c settings = Custom_Setting_Config__c.getInstance();
discount = settings.Discount__c;
}
return discount;
}
set;
}
public static Double applyDiscount(Double value) {
return value - DISCOUNT;
}
public static Double removeTwenty(Double value){
return value = 20;
}
}
Writing your class like this, you could call DiscountUtility.applyDiscount(value);
and your class would properly set the discount
, but you could also call DiscountUtility.removeTwenty(value)
at a separate time and the Custom Setting would never have to even be called. This allows you to only initialize it when needed.
So, basically just keep in mind exactly what you need when you create these classes. They wouldn't be a big performance hit with the scenario described above, but it all adds up over time. Need to keep all of this stuff in mind.
In theory, you use static initializers for the scenario that Jesse described - as the de facto constructor logic in a static method utility class.
In practice, I almost never use them in Apex, because they incur a script statement cost with every request that executes any code in the class with the static initializer. Your utility classes have to be pretty narrow in scope, or unified in their prerequisite state, for blanket static initialization logic make sense.
It's a common misconception (from Java, .NET etc) that Apex static data outlives the request. It doesn't; static still (like everything else stateful) dies at the end of the request. So while in Java a static initializer will typically only run once in your entire VM lifetime, in Apex it will run up to once per request.
So you can use them for constructor-style logic, but you should prefer lazy initialization (in both static and instance initializers) if that logic is not needed every time you run any method in the class. I prefer lazy initialization almost 100% of the time in Apex.