Apex Class

Apex Class & Business Logic Practice Problems

33 free Salesforce Apex challenges · Full problem statements, best-practice notes, and step-by-step hints · Solve live on ApexArena

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.

On this page
  1. 1. Temperature Converter Utility Class
  2. 2. Opportunity Stage Helper
  3. 3. String Utilities Class
  4. 4. Math Helper Class
  5. 5. Account Service Class
  6. 6. Tiered Discount Calculator
  7. 7. RecordType ID Finder
  8. 8. JSON Response Parser
  9. 9. HTTP Callout with Retry Logic
  10. 10. Batch Apex: Deactivate Old Contacts
  11. 11. Custom Exception Classes
  12. 12. Queueable Apex: Send Welcome Email
  13. 13. Selector Layer: Contact Selector
  14. 14. Lead Score Calculator
  15. 15. Opportunity Stage Transition Validator
  16. 16. Territory Region Mapper
  17. 17. Apex REST Account Service
  18. 18. HTTP Callout Handler with Mock Support
  19. 19. Custom Exception Hierarchy
  20. 20. String Utility: Reverse Words in a Sentence
  21. 21. Word Frequency Counter
  22. 22. Factorial Calculator
  23. 23. FizzBuzz: Apex Edition
  24. 24. AccountTierService: Classify Account Revenue Tier
  25. 25. DiscountApprovalService: Route Discount Approval by Level
  26. 26. AccountHealthService: Calculate Multi-Factor Health Score
  27. 27. Apex Class: Lead Qualifier — Grade by Employees & Budget
  28. 28. Apex Class: Invoice Calculator — Discount & Tax
  29. 29. Apex Class: Phone Formatter — US Format (XXX) XXX-XXXX
  30. 30. Apex Class: SLA Checker — Is Case SLA Breached?
  31. 31. Apex Class: Name Formatter — Salutation + Full Name
  32. 32. Apex Service Class: Merge Duplicate Contacts by Account
  33. 33. Apex Service Class: Account Health Score (Bulk-Safe)
Easy Apex Class

1. Temperature Converter Utility Class

Problem #21 · Salesforce Apex Coding Challenge

Problem Statement

Create a utility class TemperatureConverter with two static methods:

  • celsiusToFahrenheit(Decimal c) → returns Decimal
  • fahrenheitToCelsius(Decimal f) → returns Decimal

Formulas: F = C × 9/5 + 32  |  C = (F − 32) × 5/9

Constraints

  • Handle null input — return null if input is null
  • Round to 2 decimal places
Approach
  • 1Use Decimal.setScale(2, RoundingMode.HALF_UP) or .setScale(2) to round.
  • 2Guard against null: if (c == null) return null;
Easy Apex Class

2. Opportunity Stage Helper

Problem #23 · Salesforce Apex Coding Challenge

Problem Statement

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".

Approach
  • 1Use equalsIgnoreCase() for case-insensitive comparison.
  • 2Guard null: if (stage == null) return false;
Easy Apex Class

3. String Utilities Class

Problem #26 · Salesforce Apex Coding Challenge

Problem Statement

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 word
Approach
  • 1For palindrome: reverse the string with new StringBuilder(s).reverse().toString() or reverse the chars manually.
  • 2For words: s.split('\\s+').size() after trimming.
  • 3For capitalize: s.split(' '), capitalize each word, String.join.
Easy Apex Class

4. Math Helper Class

Problem #29 · Salesforce Apex Coding Challenge

Problem Statement

Create a class MathHelper with these static methods:

  • factorial(Integer n) — returns n! (use recursion or iteration)
  • isPrime(Integer n) — returns true if n is prime
  • fibonacci(Integer n) — returns the nth Fibonacci number (0-indexed)

Constraints

  • Handle n ≤ 0 gracefully (return 0 for fibonacci, 1 for factorial, false for isPrime)
Approach
  • 1Factorial: for (Long result = 1; n > 1; n--) result *= n;
  • 2isPrime: check divisibility from 2 to sqrt(n).
  • 3Fibonacci: iterative with two variables is simplest.
Medium Apex ClassSOQL

5. Account Service Class

Problem #32 · Salesforce Apex Coding Challenge

Problem Statement

Create a class AccountService with:

  • getHotAccounts() — returns a List<Account> where Rating = 'Hot', ordered by Name
  • deactivateSmallAccounts(Decimal maxRevenue) — sets Active__c = false on all Accounts with AnnualRevenue < maxRevenue, updates them, returns the count updated
Approach
  • 1Use WHERE Rating = 'Hot' ORDER BY Name in your SOQL.
  • 2Collect records to update in a List, then call update once outside the loop.
Easy Apex Class

6. Tiered Discount Calculator

Problem #34 · Salesforce Apex Coding Challenge

Problem Statement

Create a class DiscountCalculator with a static method getDiscountedPrice(Decimal originalPrice, Integer quantity):

  • Quantity 1–9 → 0% discount
  • Quantity 10–49 → 10% discount
  • Quantity 50–99 → 20% discount
  • Quantity ≥ 100 → 30% discount

Returns the final price per unit after discount, rounded to 2 decimal places.

Approach
  • 1Calculate discount rate, then: originalPrice * (1 - discountRate)
  • 2.setScale(2) to round.
Medium Apex ClassSOQL

7. RecordType ID Finder

Problem #36 · Salesforce Apex Coding Challenge

Problem Statement

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.

Approach
  • 1Query: SELECT Id FROM RecordType WHERE SobjectType = :objectName AND DeveloperName = :developerName LIMIT 1
  • 2Put result in cache before returning.
Medium Apex Class

8. JSON Response Parser

Problem #38 · Salesforce Apex Coding Challenge

Problem Statement

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.

Approach
  • 1Define an inner class: class ContactJson { public String name; public String email; }
  • 2Use JSON.deserialize(jsonStr, List.class) to parse.
  • 3Map name → LastName, email → Email.
Hard Apex Class

9. HTTP Callout with Retry Logic

Problem #41 · Salesforce Apex Coding Challenge

Problem Statement

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.

Approach
  • 1HttpRequest req = new HttpRequest(); req.setEndpoint(endpoint); req.setMethod('GET');
  • 2HttpResponse res = new Http().send(req);
  • 3if (res.getStatusCode() == 200) return res.getBody();
Hard Apex ClassBatch

10. Batch Apex: Deactivate Old Contacts

Problem #43 · Salesforce Apex Coding Challenge

Problem Statement

Create a Batch Apex class DeactivateOldContactsBatch that:

  • Implements Database.Batchable<SObject>
  • Queries all Contacts where LastActivityDate < 365 days ago
  • Sets Active__c = false on each Contact in the execute method
  • Has a finish method that sends an email summary
Approach
  • 1Date cutoff = Date.today().addDays(-365);
  • 2Query: SELECT Id, Active__c FROM Contact WHERE LastActivityDate < :cutoff
  • 3In finish: use Messaging.sendEmail() or just log.
Easy Apex Class

11. Custom Exception Classes

Problem #45 · Salesforce Apex Coding Challenge

Problem Statement

Create a class AccountValidator with a custom exception InvalidAccountException (extends Exception).

Add a static method validate(Account acc) that throws InvalidAccountException if:

  • Account Name is blank
  • AnnualRevenue is negative

Returns true if valid.

Approach
  • 1throw new InvalidAccountException('Name cannot be blank');
  • 2if (acc.AnnualRevenue != null && acc.AnnualRevenue < 0) throw ...
Hard Apex ClassAsync

12. Queueable Apex: Send Welcome Email

Problem #48 · Salesforce Apex Coding Challenge

Problem Statement

Create a Queueable Apex class WelcomeEmailQueueable that:

  • Implements Queueable
  • Accepts a List<Id> of Contact IDs in its constructor
  • In execute(): queries the contacts, sends a welcome email to each
  • Enqueued with System.enqueueJob()
Approach
  • 1Query: SELECT Id, Email, FirstName FROM Contact WHERE Id IN :contactIds
  • 2Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
  • 3Messaging.sendEmail(new List{ mail });
Medium Apex ClassSOQL

13. Selector Layer: Contact Selector

Problem #49 · Salesforce Apex Coding Challenge

Problem Statement

Implement a selector class ContactSelector following enterprise patterns:

  • getByIds(Set<Id> ids) — returns Contacts by ID with standard fields
  • getByAccountId(Id accountId) — returns Contacts for an Account
  • getByEmail(String email) — returns a Contact matching the email

All queries must select: Id, FirstName, LastName, Email, Phone, AccountId

Approach
  • 1Use Database.query(BASE_FIELDS + ' WHERE Id IN :ids') for dynamic queries.
  • 2For getByEmail use LIMIT 1 and return the first result or null.
Medium Apex Classes

14. Lead Score Calculator

Problem #70 · Salesforce Apex Coding Challenge

Problem Statement

Write an Apex class LeadScorer with a static method calculateScore that computes a numeric lead score based on attributes.

Scoring rules:

  • Industry: Technology = +30, Finance = +25, Healthcare = +20, other = +10
  • Annual Revenue: >= 10,000,000 = +40, >= 1,000,000 = +25, >= 100,000 = +10, else 0
  • Employee Count: >= 1000 = +20, >= 100 = +10, else 0
  • Has Phone: +5 if phone is not null/blank
  • Has Email: +5 if email is not null/blank

Maximum possible score: 100

Method Signature

static Integer calculateScore(String industry, Decimal annualRevenue, Integer employees, String phone, String email)

Constraints

  • All parameters may be null — treat null numeric fields as 0
  • Return an Integer score (0–100)
Approach
  • 1Use if/else if chains for each scoring category
  • 2Guard against null with a null check before comparing numbers
  • 3String.isBlank() checks both null and empty — but use != null && !phone.equals('') style for compatibility
Medium Apex Classes

15. Opportunity Stage Transition Validator

Problem #71 · Salesforce Apex Coding Challenge

Problem Statement

Write an Apex class StageValidator with a static method isValidTransition that enforces allowed stage progressions for Opportunities.

Allowed transitions:

  • Prospecting → Qualification, Closed Lost
  • Qualification → Needs Analysis, Closed Lost
  • Needs Analysis → Value Proposition, Closed Lost
  • Value Proposition → Id. Decision Makers, Closed Lost
  • Id. Decision Makers → Perception Analysis, Closed Lost
  • Perception Analysis → Proposal/Price Quote, Closed Lost
  • Proposal/Price Quote → Negotiation/Review, Closed Lost
  • Negotiation/Review → Closed Won, Closed Lost
  • Closed Won → (no transitions allowed)
  • Closed Lost → (no transitions allowed)

Method Signature

static Boolean isValidTransition(String fromStage, String toStage)

Constraints

  • Return true only for explicitly listed transitions
  • Staying in the same stage returns false
  • Null inputs return false
Approach
  • 1Use a Map> to store allowed next stages for each current stage
  • 2Check containsKey before calling get to avoid null pointer
  • 3Use List.contains() to test if toStage is in the allowed set
Easy Apex Classes

16. Territory Region Mapper

Problem #72 · Salesforce Apex Coding Challenge

Problem Statement

Write an Apex class TerritoryMapper with a static method getRegion that maps US state codes to sales regions.

Region mappings:

  • Northeast: ME, NH, VT, MA, RI, CT, NY, NJ, PA
  • Southeast: DE, MD, VA, WV, NC, SC, GA, FL, AL, MS, TN, KY, AR, LA
  • Midwest: OH, IN, IL, MI, WI, MN, IA, MO, ND, SD, NE, KS
  • Southwest: TX, OK, NM, AZ
  • West: CO, WY, MT, ID, WA, OR, CA, NV, UT, AK, HI
  • Unknown state codes return 'Unknown'

Method Signature

static String getRegion(String stateCode)

Constraints

  • State codes are uppercase 2-letter abbreviations
  • Null or blank input returns 'Unknown'
  • Case-insensitive matching (normalize to uppercase)
Approach
  • 1Use a Map where each state code maps to a region name
  • 2Alternatively, use a Set for each region and check containment
  • 3Remember to call toUpperCase() to normalize the input
Hard APIApex Classes

17. Apex REST Account Service

Problem #73 · Salesforce Apex Coding Challenge

Problem Statement

Create an Apex REST service that exposes Account data via HTTP endpoints.

Requirements:

  • Annotate the class with @RestResource(urlMapping='/accounts/*')
  • Implement a GET method annotated with @HttpGet that queries Accounts and returns them as a JSON-serializable list
  • Implement a POST method annotated with @HttpPost that accepts an Account name in the request body and inserts a new Account
  • Implement a DELETE method annotated with @HttpDelete that deletes an Account by ID from the URL parameter
  • Use RestContext.request and RestContext.response where needed
  • Return appropriate HTTP status codes (200, 201, 400, 404)

Constraints

  • All methods must be global static
  • Handle the case where the record is not found (404)
  • Use try/catch for DML operations
Approach
  • 1Use RestContext.request.requestURI to extract the record ID from the URL
  • 2Set RestContext.response.statusCode = 201 after a successful insert
  • 3Deserialize the POST body with JSON.deserialize() or RestContext.request.requestBody.toString()

Halfway there — solve them live

Every 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 →
Hard APIApex Classes

18. HTTP Callout Handler with Mock Support

Problem #74 · Salesforce Apex Coding Challenge

Problem Statement

Build a robust HTTP callout handler class and its corresponding mock for testing.

Requirements for HttpCalloutHandler:

  • A method fetchExternalData(String endpoint) that makes an HTTP GET callout
  • Parse the JSON response into a wrapper class ApiResponse with fields: Integer statusCode, String body, Boolean success
  • If status code is 200, set success = true; otherwise false
  • Handle callout exceptions — set success=false, statusCode=500, body=exception message

Requirements for HttpCalloutHandlerMock:

  • Implement the HttpCalloutMock interface
  • Implement the respond method returning a mock 200 response

Constraints

  • Use Http, HttpRequest, HttpResponse classes
  • Set request timeout to 10000ms (10 seconds)
Approach
  • 1Use new Http().send(req) to make the callout
  • 2Set req.setMethod('GET') and req.setEndpoint(endpoint)
  • 3req.setTimeout(10000) sets the timeout in milliseconds
  • 4For the mock, return a new HttpResponse with setStatusCode(200) and setBody('{"ok":true}')
Medium Apex Classes

19. Custom Exception Hierarchy

Problem #76 · Salesforce Apex Coding Challenge

Problem Statement

Design a robust custom exception hierarchy for a payment processing service.

Requirements:

  • Create a base exception PaymentException extending Exception
  • Create subclasses:
    • InsufficientFundsException — includes Decimal balance and Decimal required fields
    • InvalidCardException — includes String cardType field
    • PaymentGatewayException — includes Integer errorCode and String gatewayMessage
  • Write a PaymentProcessor class with method processPayment(Decimal amount, String cardType, Decimal accountBalance)
  • Throw InvalidCardException if cardType is not in ('Visa','Mastercard','Amex')
  • Throw InsufficientFundsException if accountBalance < amount
  • Otherwise return true

Constraints

  • Each custom exception must extend the appropriate parent
  • Custom fields must be set via constructor or setter before throwing
Approach
  • 1Use a Set of valid card types and check .contains(cardType)
  • 2Throw and set fields: InvalidCardException e = new InvalidCardException(); e.cardType = cardType; throw e;
  • 3Order matters: check card type before balance to match expected exception priority
Easy Apex ClassesStrings

20. String Utility: Reverse Words in a Sentence

Problem #87 · Salesforce Apex Coding Challenge

Problem Statement

Write 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.

Examples

  • "Hello World Apex""Apex World Hello"
  • "I love Salesforce""Salesforce love I"
  • null or blank → ""

Method Signature

public static String reverseWords(String sentence)
Approach
  • 1Use String.split(' ') to break into words.
  • 2Reverse the list with a simple loop or by building a new list.
  • 3Rejoin with String.join(list, ' ').
Easy Apex ClassesCollections

21. Word Frequency Counter

Problem #88 · Salesforce Apex Coding Challenge

Problem Statement

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).

Examples

  • ['apex','java','apex','APEX']{apex:3, java:1}
  • Empty list → empty map

Method Signature

public static Map<String, Integer> countWords(List<String> words)
Approach
  • 1Normalise each word with .toLowerCase() before counting.
  • 2Use map.containsKey() to check existing entries.
  • 3Increment with map.get(word) + 1.
Easy Apex ClassesRecursion

22. Factorial Calculator

Problem #89 · Salesforce Apex Coding Challenge

Problem Statement

Write an Apex class MathUtils with a static method factorial(Integer n) that returns n!.

Rules

  • 0! = 1 and 1! = 1
  • 5! = 120
  • Return -1 for negative inputs

Method Signature

public static Integer factorial(Integer n)
Approach
  • 10! = 1 is the base case.
  • 2Use a loop: result *= i for i from 2 to n.
  • 3Or use recursion: n * factorial(n-1).
Easy Apex ClassesControl Flow

23. FizzBuzz: Apex Edition

Problem #90 · Salesforce Apex Coding Challenge

Problem Statement

Write an Apex class FizzBuzz with a static method generate(Integer n) that returns a List<String> of 1 through n with:

  • Multiples of 3 → "Fizz"
  • Multiples of 5 → "Buzz"
  • Multiples of both → "FizzBuzz"
  • Otherwise → the number as a String

Method Signature

public static List<String> generate(Integer n)
Approach
  • 1Check divisibility with Math.mod(i, 3) == 0.
  • 2Check FizzBuzz first (divisible by both 3 and 5).
  • 3Use String.valueOf(i) to convert the number.
Easy Apex ClassesBusiness Logic

24. AccountTierService: Classify Account Revenue Tier

Problem #145 · Salesforce Apex Coding Challenge

Problem Statement

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.

Tier Definitions

Annual RevenueTier
< $50,000 or null'Bronze'
$50,000 – $249,999'Silver'
$250,000 – $999,999'Gold'
≥ $1,000,000'Platinum'

Method Signature

public static String getRevenueTier(Decimal annualRevenue)

Best Practices

  • Always handle null input gracefully — null revenue maps to 'Bronze'.
  • Use a single return per branch for clarity.
Approach
  • 1Check for null first — null revenue should default to Bronze.
  • 2Use if/else-if chains: < 50K → Bronze, < 250K → Silver, < 1M → Gold, else → Platinum.
  • 3Boundary values: 50,000 is the first Silver value; 250,000 is the first Gold value.
Easy Apex ClassesBusiness Logic

25. DiscountApprovalService: Route Discount Approval by Level

Problem #146 · Salesforce Apex Coding Challenge

Problem Statement

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.

Approval Matrix

Discount %Approval Level
null or < 0'Invalid'
0% – 5%'Rep'
>5% – 15%'Manager'
>15% – 25%'Director'
>25%'VP'

Method Signature

public static String getApprovalLevel(Decimal discountPercent)
Approach
  • 1Check null and negative values first — return "Invalid".
  • 20–5 → Rep; 5–15 → Manager; 15–25 → Director; above 25 → VP.
  • 3Use <= 5 for the Rep boundary so exactly 5% still routes to Rep.
Medium Apex ClassesBusiness LogicScoring

26. AccountHealthService: Calculate Multi-Factor Health Score

Problem #147 · Salesforce Apex Coding Challenge

Problem Statement

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.

Scoring Factors

  • Annual Revenue (0–30 pts): ≥ $1M = 30 | ≥ $500K = 20 | ≥ $100K = 10 | else 0
  • Rating (0–25 pts): 'Hot' = 25 | 'Warm' = 15 | 'Cold' = 5 | else 0
  • Industry (10–20 pts): 'Technology' or 'Finance' = 20 | else 10
  • Contact Count (0–15 pts): ≥ 10 = 15 | ≥ 5 = 10 | ≥ 1 = 5 | else 0
  • Billing State (0–10 pts): non-null/non-blank = 10 | else 0

Method Signature

public static Integer getHealthScore(String industry, Decimal annualRevenue, String rating, Integer contactCount, String billingState)
Approach
  • 1Start with revenue: if null → 0 pts; >= 1M → 30; >= 500K → 20; >= 100K → 10.
  • 2For industry, always award at least 10 pts; bump to 20 for Technology or Finance.
  • 3Guard contactCount and billingState against null before comparing.
  • 4Maximum possible score is 30 + 25 + 20 + 15 + 10 = 100.
Easy Apex Class

27. Apex Class: Lead Qualifier — Grade by Employees & Budget

Problem #280 · Salesforce Apex Coding Challenge

Problem Statement

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.

Grading Rules

  • A — employees ≥ 1,000 OR budget ≥ 500,000
  • B — employees ≥ 200 OR budget ≥ 100,000
  • C — employees ≥ 50
  • Unqualified — everything else

Requirements

  • Null-safe: treat null employees or budget as 0
  • Define thresholds as named constants (not magic numbers)
  • Use with sharing on the class
Approach
  • 1Treat null numEmployees and budget as 0 using the ternary operator.
  • 2Check the highest grade first (A), then B, C — use early returns.
  • 3Store thresholds in private static final constants to avoid magic numbers.
Easy Apex Class

28. Apex Class: Invoice Calculator — Discount & Tax

Problem #281 · Salesforce Apex Coding Challenge

Problem Statement

Write an Apex class InvoiceCalculator with a static method calculateTotal(List<Decimal> lineItems, Decimal taxRate, Decimal discountPct) that computes the final invoice total.

Formula

subtotal     = sum of all positive line items
afterDiscount = subtotal × (1 − discountPct ÷ 100)
total         = afterDiscount × (1 + taxRate ÷ 100)
Return total rounded to 2 decimal places.

Requirements

  • Skip null or negative line items
  • Treat null taxRate or discountPct as 0
  • Return 0 for null or empty line-item list
  • Round the result to 2 decimal places using .setScale(2)
Approach
  • 1Sum only items that are non-null and > 0.
  • 2Discount formula: subtotal * (1 - discountPct/100).
  • 3Tax formula: afterDiscount * (1 + taxRate/100).
  • 4Use .setScale(2) on a Decimal to round to 2 decimal places.
Easy Apex Class

29. Apex Class: Phone Formatter — US Format (XXX) XXX-XXXX

Problem #282 · Salesforce Apex Coding Challenge

Problem Statement

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.

Rules

  • Strip all non-digit characters first (dashes, dots, spaces, parens)
  • If the result is exactly 10 digits, format as (XXX) XXX-XXXX
  • If not 10 digits, return the original input unchanged
  • If blank or null, return ""

Examples

  • "415-555-1234""(415) 555-1234"
  • "4155551234""(415) 555-1234"
  • "415.555.1234""(415) 555-1234"
  • "12345""12345" (not 10 digits)
Approach
  • 1Use String.replaceAll('[^0-9]', '') to strip all non-digit characters.
  • 2String.substring(start, end) extracts a portion of the string (end is exclusive).
  • 3If digits.length() != 10, return the original rawPhone unchanged.
Easy Apex Class

30. Apex Class: SLA Checker — Is Case SLA Breached?

Problem #283 · Salesforce Apex Coding Challenge

Problem Statement

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.

SLA Thresholds

PriorityMax Hours
Critical2
High4
Medium8
Low24

Requirements

  • Return false for null/blank priority or null hoursOpen
  • Return false for unknown priority values
  • Store thresholds in a Map constant — no if-else chains
Approach
  • 1A static Map constant elegantly replaces if-else chains.
  • 2Use map.get(priority) — if it returns null, the priority is unknown.
  • 3Guard against null inputs before doing any comparison.
Easy Apex Class

31. Apex Class: Name Formatter — Salutation + Full Name

Problem #284 · Salesforce Apex Coding Challenge

Problem Statement

Write an Apex class NameFormatter with two static methods:

Method 1 — fullName

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"

Method 2 — lastFirst

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"

Requirements

  • Skip blank/null parts — do not produce leading/trailing spaces
  • Use String.isBlank() for null-safe blank checks
Approach
  • 1Build a List, add only non-blank parts, then String.join(list, ' ').
  • 2String.isBlank() returns true for null, empty, and whitespace-only strings.
  • 3For lastFirst, handle each missing-part edge case separately.
Medium Apex Classes

32. Apex Service Class: Merge Duplicate Contacts by Account

Problem #357 · Salesforce Apex Coding Challenge

Problem Statement

Write 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.

Requirements

  • public with sharing class.
  • Throw IllegalArgumentException when accountId is null.
  • Query Contacts ordered by CreatedDate ASC; group by full name (case-insensitive).
  • Call Database.merge(master, List<Id>) with up to 2 IDs per call.
  • System.debug the merged count — visible in the Output tab.
  • Return the total number of merged records.
Approach
  • 1Full name key: String key = ((c.FirstName != null ? c.FirstName : '') + ' ' + c.LastName).trim().toLowerCase();
  • 2ORDER BY CreatedDate ASC puts the oldest first — that becomes the master at index 0.
  • 3Database.merge(master, chunk) accepts a List with up to 2 entries. Use a while loop with idx += chunk.size().
  • 4WITH SECURITY_ENFORCED on SOQL enforces field-level security — required for service classes.
Medium Apex Classes

33. Apex Service Class: Account Health Score (Bulk-Safe)

Problem #358 · Salesforce Apex Coding Challenge

Problem Statement

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.

Scoring Rules (0–100, clamped)

  • +40 — open Opportunity
  • +30 — Closed Won in last 12 months
  • +20 — LastActivityDate within 90 days
  • −30 — open Case
Approach
  • 1Aggregate pattern: for (AggregateResult ar : [SELECT AccountId acctId FROM Opportunity WHERE AccountId IN :accountIds AND IsClosed = false WITH SECURITY_ENFORCED GROUP BY AccountId]) { hasOpenOpps.add((Id) ar.get('acctId')); }
  • 2Clamp: score = Math.max(0, Math.min(100, score)); — ensures the result is always in [0, 100].
  • 3The single-account method delegates: Map r = calculateHealthScores(new Set{ accountId }); return r.containsKey(accountId) ? r.get(accountId) : 0;
  • 4Use System.debug to print the score so it shows in the Console/Output tab after running.

Practice All 33 Problems Free

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 Problems
More Practice Topics
About ApexArena

ApexArena 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