1. What is asynchronous Apex, and why would you use it?
Asynchronous Apex runs in a separate thread from the user’s transaction, at a later time, rather than blocking the user’s immediate interaction. It’s used for long-running operations, callouts, bulk processing, or scheduled jobs — anything that shouldn’t hold up the user interface or that needs higher governor limits than synchronous execution allows.
2. What are the four main types of asynchronous Apex?
Future methods, Queueable Apex, Batch Apex, and Scheduled Apex. Each solves a different problem: Future methods handle simple fire-and-forget tasks, Queueable adds chaining and complex parameter support, Batch Apex processes very large data volumes in chunks, and Scheduled Apex runs code at a specific time or on a recurring basis.
3. What is a Future method, and what are its limitations?
A Future method is a static method annotated with @future that runs asynchronously. Its main limitations are that it can only accept primitive data types or collections of primitives as parameters (no sObjects), it can’t be chained to call another future method, and you can’t track its execution status directly.
public class AsyncService {
@future
public static void updateAccounts(Set<Id> accountIds) {
List<Account> accs = [SELECT Id, Description FROM Account WHERE Id IN :accountIds];
for (Account a : accs) {
a.Description = 'Updated asynchronously';
}
update accs;
}
}4. What is Queueable Apex, and how is it different from a Future method?
Queueable Apex implements the Queueable interface and offers advantages Future methods lack: it accepts complex, non-primitive parameters (including sObjects), supports job chaining (one queueable job enqueuing another), and returns a job Id you can use to monitor status via AsyncApexJob.
public class UpdateAccountsQueueable implements Queueable {
private List<Account> accounts;
public UpdateAccountsQueueable(List<Account> accounts) {
this.accounts = accounts;
}
public void execute(QueueableContext context) {
update accounts;
}
}5. How do you chain Queueable jobs together?
Inside the execute() method of one Queueable class, you call System.enqueueJob() with a new instance of the next Queueable class. Salesforce allows chaining, but be mindful of the chain depth limits enforced per context (5 in most contexts, unlimited in some Enterprise/Unlimited editions, though best practice is to avoid excessively long chains).
public void execute(QueueableContext context) {
// do work
System.enqueueJob(new NextStepQueueable());
}6. What is Batch Apex, and when should you use it?
Batch Apex implements the Database.Batchable interface and processes large numbers of records (up to 50 million) by splitting them into smaller batches (default 200 records), each executed in its own governor-limit context. It’s the right choice when a Future or Queueable job would exceed limits due to sheer data volume.
public class UpdateAllAccountsBatch implements Database.Batchable<sObject> {
public Database.QueryLocator start(Database.BatchableContext bc) {
return Database.getQueryLocator('SELECT Id, Description FROM Account');
}
public void execute(Database.BatchableContext bc, List<Account> scope) {
for (Account a : scope) {
a.Description = 'Batch updated';
}
update scope;
}
public void finish(Database.BatchableContext bc) {
// post-processing, e.g., send a summary email
}
}7. What are the three methods every Batch Apex class must implement?
start(), which defines the scope of records to process (via a QueryLocator or Iterable); execute(), which runs once per batch of records (called multiple times); and finish(), which runs once after all batches complete, often used for follow-up actions like sending a summary email or chaining another batch job.
8. How do you control the batch size in Batch Apex?
You pass a second parameter to Database.executeBatch() specifying the number of records per batch (default is 200, maximum is 2000):
Database.executeBatch(new UpdateAllAccountsBatch(), 100);9. What is Scheduled Apex, and how do you implement it?
Scheduled Apex runs code at specified times using the Schedulable interface and a CRON expression. It’s commonly used to trigger a Batch Apex job on a recurring schedule (e.g., nightly data cleanup).
public class NightlyCleanupScheduler implements Schedulable {
public void execute(SchedulableContext sc) {
Database.executeBatch(new UpdateAllAccountsBatch());
}
}String cronExp = '0 0 2 * * ?'; // every day at 2 AM
System.schedule('Nightly Cleanup', cronExp, new NightlyCleanupScheduler());10. What is the maximum number of batch jobs that can be queued or active at once?
An org can have up to 5 batch jobs queued or actively processing at the same time. Attempting to queue a 6th throws a LimitException, which is a common real-world gotcha when multiple automated processes try to launch batches simultaneously.
11. Why can’t you make a callout directly inside a trigger?
Triggers execute within the same transaction as the DML that fired them, and Salesforce doesn’t allow synchronous callouts within that context because it would leave the database transaction open and waiting on an external system for an unpredictable amount of time. The workaround is to make the callout asynchronously, typically via a Future method or Queueable class.
12. What is the difference between a checked and unchecked exception in Apex?
Apex doesn’t formally distinguish checked vs. unchecked exceptions the way Java does — all Apex exceptions are effectively unchecked, meaning the compiler doesn’t force you to catch them. However, custom exceptions (extending the built-in Exception class) are commonly used to represent expected, catchable business logic errors.
public class InvalidDiscountException extends Exception {}
if (discount > 100) {
throw new InvalidDiscountException('Discount cannot exceed 100%');
}13. What is the difference between DmlException and QueryException?
DmlException is thrown when a DML operation (insert/update/delete) fails, typically due to validation rules, required fields, or triggers throwing errors. QueryException is thrown when a SOQL query fails or returns unexpected results, such as calling .get(0) on an empty list or assigning a multi-row query result to a single sObject variable.
14. What is a custom exception class in Apex, and why create one?
A custom exception class extends the built-in Exception class, letting you represent specific, meaningful error conditions in your application (like InsufficientInventoryException) rather than relying on generic exception types. This makes error handling in calling code more precise and readable.
15. What happens if you don’t catch an exception in Apex?
If an exception isn’t caught, it propagates up the call stack, and if nothing catches it, the entire transaction is rolled back and an unhandled exception error is returned to the user or calling process (which can look like a generic, unhelpful error in an LWC or integration if not handled properly).
16. What is the purpose of a finally block in Apex exception handling?
Code inside a finally block always executes after the try (and catch, if triggered) block, regardless of whether an exception occurred — commonly used for cleanup logic that must run no matter what, like closing a resource or logging that an operation completed.
try {
processRecords();
} catch (Exception e) {
System.debug('Error: ' + e.getMessage());
} finally {
System.debug('Processing attempt finished');
}17. What is the difference between with sharing, without sharing, and inherited sharing?
with sharing enforces the running user’s record-level sharing rules within that class. without sharing explicitly ignores sharing rules, running with full object access regardless of the user (Apex’s default behavior if unspecified, which is why explicitly declaring it matters). inherited sharing makes the class adopt whatever sharing context it was called from, giving more flexibility for utility classes reused across different contexts.
18. Why does sharing enforcement matter in Apex, and where is it commonly tested in interviews?
Sharing rules only restrict record-level visibility, not object or field-level permissions — those come from profiles and permission sets separately. Interviewers often test whether you know that leaving a class as the Apex default (without sharing behavior) can unintentionally expose or modify records a user shouldn’t have access to, which is a real security review finding in many orgs.
19. What is Security.stripInaccessible() used for?
It’s a method that removes field values a running user doesn’t have access to from a list of sObjects before they’re returned to the client, helping enforce field-level security (FLS) explicitly in Apex — since SOQL queries themselves don’t automatically respect FLS by default.
SObjectAccessDecision decision = Security.stripInaccessible(
AccessType.READABLE, accountList
);
List<Account> safeAccounts = decision.getRecords();20. What is the difference between enforcing sharing rules and enforcing field-level security (FLS) in Apex?
Sharing rules (with sharing) control which records a user can see or edit based on ownership, role hierarchy, and sharing settings. FLS controls which fields on a record a user is allowed to view or edit, and must be checked separately (using Security.stripInaccessible(), WITH SECURITY_ENFORCED in SOQL, or manual Schema.sObjectField checks) since sharing rules alone don’t restrict field visibility.
No comments:
Post a Comment