This guide walks through 33 general-purpose Apex classes — collections, string handling, business logic, and service-layer design. Each entry below includes the full problem statement, the governor-limit and best-practice constraints it's testing, and a numbered approach to solving it — then you can open the same problem in ApexArena's browser-based Apex editor and get instant pass/fail feedback against real test cases.
Create a utility class TemperatureConverter with two static methods:
celsiusToFahrenheit(Decimal c) → returns DecimalfahrenheitToCelsius(Decimal f) → returns DecimalFormulas: F = C × 9/5 + 32 | C = (F − 32) × 5/9
Create a class OpportunityHelper with a static method
isWon(String stage) that returns true if the stage equals
"Closed Won" (case-insensitive), otherwise false.
Also add isLost(String stage) that returns true for "Closed Lost".
Create a class StringUtils with these static methods:
isPalindrome(String s) — returns true if s reads the same forwards and backwards (ignore case)countWords(String s) — returns the number of words (split on whitespace)capitalizeFirst(String s) — capitalizes the first letter of every wordCreate a class MathHelper with these static methods:
factorial(Integer n) — returns n! (use recursion or iteration)isPrime(Integer n) — returns true if n is primefibonacci(Integer n) — returns the nth Fibonacci number (0-indexed)Create a class AccountService with:
getHotAccounts() — returns a List<Account> where Rating = 'Hot', ordered by NamedeactivateSmallAccounts(Decimal maxRevenue) — sets Active__c = false on all Accounts with AnnualRevenue < maxRevenue, updates them, returns the count updatedCreate a class DiscountCalculator with a static method
getDiscountedPrice(Decimal originalPrice, Integer quantity):
Returns the final price per unit after discount, rounded to 2 decimal places.
Create a class RecordTypeHelper with a static method:
getId(String objectName, String developerName)
Returns the Id of the RecordType matching the given sObject name and
developer name, or null if not found.
Must cache results in a static Map so subsequent calls for the same object don't trigger more SOQL.
Create a class JsonParser with a static method
parseContacts(String jsonStr) that parses a JSON array of objects like:
[{"name":"Alice","email":"alice@x.com"},{"name":"Bob","email":"bob@x.com"}]
Returns a List<Contact> with LastName set from name
and Email set from email.
Create a class HttpCalloutService with a method
callWithRetry(String endpoint, Integer maxRetries).
It should make an HTTP GET request, and if the response status is not 200,
retry up to maxRetries times with a 1-second delay between attempts.
Return the response body on success, or throw a CalloutException after all retries are exhausted.
Create a Batch Apex class DeactivateOldContactsBatch that:
Database.Batchable<SObject>LastActivityDate < 365 days agoActive__c = false on each Contact in the execute methodCreate a class AccountValidator with a custom exception
InvalidAccountException (extends Exception).
Add a static method validate(Account acc) that throws
InvalidAccountException if:
Returns true if valid.
Create a Queueable Apex class WelcomeEmailQueueable that:
QueueableList<Id> of Contact IDs in its constructorexecute(): queries the contacts, sends a welcome email to eachSystem.enqueueJob()Implement a selector class ContactSelector following enterprise patterns:
getByIds(Set<Id> ids) — returns Contacts by ID with standard fieldsgetByAccountId(Id accountId) — returns Contacts for an AccountgetByEmail(String email) — returns a Contact matching the emailAll queries must select: Id, FirstName, LastName, Email, Phone, AccountId
Write an Apex class LeadScorer with a static method calculateScore
that computes a numeric lead score based on attributes.
Scoring rules:
Maximum possible score: 100
static Integer calculateScore(String industry, Decimal annualRevenue, Integer employees, String phone, String email)
Write an Apex class StageValidator with a static method isValidTransition
that enforces allowed stage progressions for Opportunities.
Allowed transitions:
static Boolean isValidTransition(String fromStage, String toStage)
Write an Apex class TerritoryMapper with a static method getRegion
that maps US state codes to sales regions.
Region mappings:
'Unknown'static String getRegion(String stateCode)
'Unknown'Create an Apex REST service that exposes Account data via HTTP endpoints.
Requirements:
@RestResource(urlMapping='/accounts/*')GET method annotated with @HttpGet that queries Accounts
and returns them as a JSON-serializable listPOST method annotated with @HttpPost that accepts an
Account name in the request body and inserts a new AccountDELETE method annotated with @HttpDelete that deletes
an Account by ID from the URL parameterRestContext.request and RestContext.response where neededglobal staticEvery problem above runs in a real in-browser Apex editor with instant pass/fail feedback and best-practice linting. No Salesforce org needed.
Create Free Account →Build a robust HTTP callout handler class and its corresponding mock for testing.
Requirements for HttpCalloutHandler:
fetchExternalData(String endpoint) that makes an HTTP GET calloutApiResponse with fields:
Integer statusCode, String body, Boolean successRequirements for HttpCalloutHandlerMock:
HttpCalloutMock interfacerespond method returning a mock 200 responseHttp, HttpRequest, HttpResponse classesDesign a robust custom exception hierarchy for a payment processing service.
Requirements:
PaymentException extending ExceptionInsufficientFundsException — includes Decimal balance and Decimal required fieldsInvalidCardException — includes String cardType fieldPaymentGatewayException — includes Integer errorCode and String gatewayMessagePaymentProcessor class with method processPayment(Decimal amount, String cardType, Decimal accountBalance)InvalidCardException if cardType is not in ('Visa','Mastercard','Amex')InsufficientFundsException if accountBalance < amounttrueWrite an Apex class StringUtils with a static method
reverseWords(String sentence) that reverses the order of words
in a sentence while preserving each word's characters.
"Hello World Apex" → "Apex World Hello""I love Salesforce" → "Salesforce love I"null or blank → ""public static String reverseWords(String sentence)
Write an Apex class WordCounter with a static method
countWords(List<String> words) that returns a
Map<String, Integer> counting the frequency of each word
(case-insensitive).
['apex','java','apex','APEX'] → {apex:3, java:1}public static Map<String, Integer> countWords(List<String> words)
Write an Apex class MathUtils with a static method
factorial(Integer n) that returns n!.
0! = 1 and 1! = 15! = 120-1 for negative inputspublic static Integer factorial(Integer n)
Write an Apex class FizzBuzz with a static method
generate(Integer n) that returns a List<String>
of 1 through n with:
"Fizz""Buzz""FizzBuzz"public static List<String> generate(Integer n)
Your sales operations team needs to automatically classify accounts into revenue tiers to determine service level agreements and pricing models.
Write an Apex class AccountTierService with a static method
getRevenueTier(Decimal annualRevenue) that returns a tier label based on the account's annual revenue.
| Annual Revenue | Tier |
|---|---|
| < $50,000 or null | 'Bronze' |
| $50,000 – $249,999 | 'Silver' |
| $250,000 – $999,999 | 'Gold' |
| ≥ $1,000,000 | 'Platinum' |
public static String getRevenueTier(Decimal annualRevenue)
null input gracefully — null revenue maps to 'Bronze'.Your finance team requires that discount approvals are routed to the correct authority level based on the percentage discount being offered on an opportunity.
Write an Apex class DiscountApprovalService with a static method
getApprovalLevel(Decimal discountPercent) that returns the required approver.
| Discount % | Approval Level |
|---|---|
| null or < 0 | 'Invalid' |
| 0% – 5% | 'Rep' |
| >5% – 15% | 'Manager' |
| >15% – 25% | 'Director' |
| >25% | 'VP' |
public static String getApprovalLevel(Decimal discountPercent)
Your account management team needs a single numeric health score (0–100) per account to prioritise outreach. The score is calculated from five weighted factors.
Write an Apex class AccountHealthService with a static method
getHealthScore(String industry, Decimal annualRevenue, String rating,
Integer contactCount, String billingState) that returns an Integer score.
public static Integer getHealthScore(String industry, Decimal annualRevenue, String rating, Integer contactCount, String billingState)
Write an Apex class LeadQualifier with a static method
qualify(String source, Integer numEmployees, Decimal budget)
that returns a letter grade based on company size and budget.
with sharing on the classWrite an Apex class InvoiceCalculator with a static method
calculateTotal(List<Decimal> lineItems, Decimal taxRate, Decimal discountPct)
that computes the final invoice total.
subtotal = sum of all positive line items afterDiscount = subtotal × (1 − discountPct ÷ 100) total = afterDiscount × (1 + taxRate ÷ 100) Return total rounded to 2 decimal places.
.setScale(2)Write an Apex class PhoneFormatter with a static method
formatPhone(String rawPhone) that formats any 10-digit US phone
number into the standard (XXX) XXX-XXXX pattern.
(XXX) XXX-XXXX"""415-555-1234" → "(415) 555-1234""4155551234" → "(415) 555-1234""415.555.1234" → "(415) 555-1234""12345" → "12345" (not 10 digits)Write an Apex class SLAChecker with a static method
isBreached(String priority, Integer hoursOpen) that returns
true when a case has exceeded its SLA time limit.
| Priority | Max Hours |
|---|---|
| Critical | 2 |
| High | 4 |
| Medium | 8 |
| Low | 24 |
false for null/blank priority or null hoursOpenfalse for unknown priority valuesMap constant — no if-else chainsWrite an Apex class NameFormatter with two static methods:
public static String fullName(String salutation, String firstName, String lastName)
Concatenates non-blank parts separated by a single space.
e.g. fullName("Mr.", "John", "Smith") → "Mr. John Smith"
e.g. fullName(null, "John", "Smith") → "John Smith"
public static String lastFirst(String firstName, String lastName)
Returns "Last, First" format.
e.g. lastFirst("John", "Smith") → "Smith, John"
e.g. lastFirst(null, "Smith") → "Smith"
String.isBlank() for null-safe blank checksWrite a service class ContactMergeService with a static method
mergeContactsByAccount(Id accountId) that merges duplicate Contacts
under the same Account.
Two Contacts are duplicates when they share the same full name (case-insensitive).
The oldest Contact (earliest CreatedDate) is kept as the master record.
public with sharing class.IllegalArgumentException when accountId is null.CreatedDate ASC; group by full name (case-insensitive).Database.merge(master, List<Id>) with up to 2 IDs per call.System.debug the merged count — visible in the Output tab.Write AccountHealthScoreService with two static methods:
calculateHealthScore(Id accountId) — single-account wrapper that System.debugs the score.calculateHealthScores(Set<Id> accountIds) — bulk-safe: exactly 4 SOQL queries total.Write and run real Apex code right in your browser — instant pass/fail feedback, best-practice linting, and governor limit monitoring. No Salesforce org needed.
Create Free Account → Explore All ProblemsApexArena is a free, browser-based Salesforce Apex coding practice platform covering every major topic tested on the Salesforce Platform Developer I (PD1) and Platform Developer II (PD2) certification exams. All problems run directly in your browser with instant pass/fail feedback, best-practice linting (SOQL in loops, DML in loops, empty catch blocks), and governor limit monitoring — no Salesforce Developer Edition org required.
Related tutorials: Apex Triggers · SOQL · Batch Apex · Interview Q&A · Governor Limits