Ora

How do I set a global variable in Apex?

Published in Apex Development 6 mins read

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: The static 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:

  1. Choose an Access Modifier: Select the appropriate visibility (public, private, protected, global). public or global modifiers allow access from other classes.
  2. Use the static Keyword: This is mandatory to designate a class-level variable that is shared.
  3. Specify Data Type: Declare the variable's data type (e.g., String, Integer, List<Id>, custom SObject).
  4. 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.