In Apex, you set a "global variable" by defining a static
variable within a class, which allows it to be shared across all instances of that class and accessible throughout the current Apex transaction.
When developers refer to "global variables" in Apex, they typically mean static variables (also known as class variables). Unlike instance variables that belong to a specific object, static variables belong to the class itself. This means their value is shared across all instances of the class and persists for the duration of a single Apex transaction.
Understanding Static Variables in Apex
Static variables are fundamental for managing shared data or properties that do not rely on object instantiation. They are initialized once when the class is loaded and retain their state for the entire lifecycle of an Apex transaction.
Key Characteristics:
- Class-Level Scope: Static variables are defined directly within the class, outside of any methods, constructors, or other code blocks.
- Shared State: All instances of the class within the same transaction share the exact same copy of the static variable.
- Transaction-Bound: Their values are maintained throughout the execution of a single Apex transaction but are reset for subsequent transactions.
static
Keyword: Thestatic
keyword is essential for declaring a variable as a class variable.
How to Define a Static Variable
To create what functions as a "global variable" in Apex, you must declare it using the static
keyword. The variable needs to be placed at the top level of the class, specifying its data type, and you can optionally assign an initial value upon declaration.
Here's the basic syntax:
public class SharedVariables {
// Define a public static variable (acts like a global constant)
public static final Integer MAX_OPERATION_LIMIT = 10;
// Define a private static variable for internal class use
private static String currentProcessStatus = 'Pending';
// Define a static list to accumulate IDs processed in the transaction
public static List<Id> processedItemIds = new List<Id>();
// Define a static counter
public static Integer transactionEventCounter = 0;
public SharedVariables() {
// Constructor can access static variables
transactionEventCounter++;
}
public static void logProcessState(String message) {
// Static methods can access static variables directly
System.debug('Process Status: ' + currentProcessStatus + ' - ' + message);
}
public void updateProcessStatus(String newStatus) {
// Instance methods can also access static variables
currentProcessStatus = newStatus;
}
}
Practical Steps for Defining:
- Choose an Access Modifier: Select the appropriate visibility (
public
,private
,protected
,global
).public
orglobal
modifiers allow access from other classes. - Use the
static
Keyword: This is mandatory to designate a class-level variable that is shared. - Specify Data Type: Declare the variable's data type (e.g.,
String
,Integer
,List<Id>
, custom SObject). - Provide an Initial Value (Recommended): Assign a default value when declaring the variable for clarity and to prevent
null
pointer exceptions.
Accessing Static Variables
Accessing static variables is straightforward and does not require an instance of the class to be created.
From Within the Same Class:
You can access static variables directly by their name.
public class SharedVariables {
public static Integer transactionEventCounter = 0;
public void incrementCounter() {
transactionEventCounter++; // Accessed directly
}
public static void displayCounter() {
System.debug('Current Event Counter: ' + transactionEventCounter); // Accessed directly in a static method
}
}
From Other Classes:
To access a public
or global
static variable from another class, use the class name followed by the dot operator and the variable name.
public class ExternalProcessor {
public void executeBatchOperations() {
// Access a static variable from SharedVariables class
SharedVariables.transactionEventCounter++;
System.debug('Counter from ExternalProcessor: ' + SharedVariables.transactionEventCounter);
// Access a static constant
Integer limit = SharedVariables.MAX_OPERATION_LIMIT;
System.debug('Maximum operations allowed: ' + limit);
}
}
Common Use Cases for Static Variables
Static variables are exceptionally useful for scenarios requiring shared data within a single Apex transaction:
- Counters: Tracking the number of times a specific action (e.g., DML operations, API calls) occurs within a transaction.
- Flags/Switches: Implementing boolean flags to control logic flow, such as preventing recursive trigger execution.
- Caches: Storing data that is expensive to retrieve (e.g., query results) for reuse multiple times within the same transaction, reducing query limits.
- Constants: Defining fixed values that improve code readability and maintainability (e.g.,
public static final String STATUS_ACTIVE = 'Active';
). - Collections: Accumulating data (e.g.,
List<SObject> recordsToInsert
) to perform a single, bulk DML operation at the end of a transaction, optimizing governor limits.
Example: Preventing Trigger Recursion
A classic application of static variables is to prevent Apex triggers from executing repeatedly within the same transaction, which can lead to infinite loops or governor limit exceptions.
public class AccountTriggerHandler {
// Static variable to control trigger recursion
public static Boolean isFirstRun = true;
public static void afterUpdate(List<Account> newAccounts) {
if (isFirstRun) {
isFirstRun = false; // Set to false to prevent re-entry for this transaction
List<Account> accountsToProcess = new List<Account>();
for (Account acc : newAccounts) {
if (acc.Description != 'Updated by Trigger Logic') {
acc.Description = 'Updated by Trigger Logic';
accountsToProcess.add(acc);
}
}
if (!accountsToProcess.isEmpty()) {
update accountsToProcess; // This DML operation could re-fire the trigger
}
}
}
}
In this example, isFirstRun
acts as a flag. The first time the trigger executes, isFirstRun
is true
, allowing the logic to proceed. It then sets isFirstRun
to false
. If the update accountsToProcess
statement causes the same trigger to fire again within the same transaction, the if (isFirstRun)
condition will now evaluate to false
, preventing the trigger's core logic from running again and thus avoiding recursion.
Static Variables vs. Instance Variables
Understanding the distinction between static and instance variables is crucial for effective Apex development.
Feature | Static Variable | Instance Variable |
---|---|---|
Belongs To | The class itself | A specific object instance |
Memory | Allocated once per class load (per transaction) | Allocated for each new object instance |
Access | ClassName.variableName or directly within class |
objectInstance.variableName |
Shared | Yes, shared by all instances of the class | No, each object instance has its own unique copy |
Lifecycle | Persists for the duration of the Apex transaction | Persists as long as its object instance exists |
Keyword | static |
None required (default) |
For further reading and official documentation on static
variables and methods, refer to the Salesforce Apex Developer Guide.
Important Considerations
- Transaction Scope: It's vital to remember that static variables are "global" only within the context of a single Apex transaction. Their values are initialized or reset at the beginning of each new transaction. They do not persist across different user sessions, separate API calls, or distinct scheduled jobs.
- Stateful Components: For maintaining state across multiple server requests in Visualforce controllers, instance variables are typically used. For modern Lightning Web Components or Aura Components, reactive properties or specific framework mechanisms manage component state.
- Serialization: Static variables are generally not included when an object is serialized or deserialized between different Apex contexts.
By correctly implementing and understanding static variables, you can effectively manage shared data, optimize performance, and build more robust and efficient Apex applications.