Skip to main content
New tool CRON Expression Builder — preview next run times before you schedule Apex. Open the builder →
Apex

Apex String Class: 30 Methods Salesforce Developers Use Daily

Every Apex String method that matters in real code — split, join, contains, trim, escape, format, and the ones that break unexpectedly with null. Plus the SOQL-injection escape pattern.

The Apex String class shows up in every nontrivial piece of Salesforce code. Knowing the right method saves you 15 minutes of stack-overflow searching plus the time to debug the inevitable null-pointer exception. This is the reference I keep open in a tab.

Strings are immutable

Before the methods: every Apex String operation returns a new String. The original is never mutated. So:

String name = 'Acme';
name.toUpperCase();  // Result discarded — name is still 'Acme'
name = name.toUpperCase();  // Now name is 'ACME'

This is identical to Java/JavaScript and unlike most C-family languages. It also means string-building in a loop allocates new objects on every iteration — use String.join instead (covered below).

Null-safety: the most important pattern

The single most useful String method is String.isBlank():

String x = null;
String.isBlank(x);   // true
String.isBlank('');  // true
String.isBlank(' '); // true (whitespace counts)
String.isBlank('x'); // false

String.isNotBlank(x);  // false

Use it instead of x == null || x.trim() == ''. It's the safest default for "do I have a real value here?"

The 30 methods you'll actually use

'Hello World'.contains('World');           // true
'Hello World'.containsIgnoreCase('world'); // true
'Hello World'.startsWith('Hello');         // true
'Hello World'.endsWith('World');           // true
'Hello World'.indexOf('World');            // 6 (position; -1 if not found)
'Hello World'.lastIndexOf('o');            // 7

Case manipulation

'Hello'.toUpperCase();          // 'HELLO'
'Hello'.toLowerCase();          // 'hello'
'Hello'.capitalize();           // 'Hello' (no-op if already capitalized)
'hello world'.equalsIgnoreCase('HELLO WORLD'); // true

Trimming and padding

'  hi  '.trim();                // 'hi'
'  hi  '.stripLeft();           // 'hi  '
'  hi  '.stripRight();          // '  hi'
'5'.leftPad(3, '0');            // '005'
'5'.rightPad(3, '*');           // '5**'

Splitting and joining

'a,b,c'.split(',');                          // ['a', 'b', 'c']
'a-b_c'.split('[-_]');                       // ['a', 'b', 'c'] (regex)
String.join(new List<String>{'a', 'b', 'c'}, ',');  // 'a,b,c'
String.join(new List<Integer>{1, 2, 3}, '-');       // '1-2-3' (auto-converts)

String.join accepts any List — auto-converts Integer, ID, etc. Best way to build a comma-separated list inside a loop:

// BAD — allocates a new String every iteration
String csv = '';
for (Account a : accounts) csv += a.Name + ',';

// GOOD
List<String> names = new List<String>();
for (Account a : accounts) names.add(a.Name);
String csv = String.join(names, ',');

Replacement

'hello'.replace('l', 'L');                // 'heLLo' (literal)
'2024-01-15'.replaceAll('-', '/');        // '2024/01/15' (regex)
'hello'.replaceFirst('l', 'L');           // 'heLlo'

Length and substring

'Hello'.length();                          // 5
'Hello World'.substring(6);                // 'World'
'Hello World'.substring(0, 5);             // 'Hello' (end-exclusive)
'Hello World'.left(5);                     // 'Hello'
'Hello World'.right(5);                    // 'World'
'Hello World'.mid(6, 5);                   // 'World' (start, length)

Conversion (the static side)

String.valueOf(42);                        // '42'
String.valueOf(Date.today());              // '2026-05-06 00:00:00'
String.valueOf(myAccount);                 // 'Account:{Id=001..., Name=Acme}'
Integer.valueOf('42');                     // 42 (parsing the other way)

String.valueOf accepts any type and returns a string representation — useful for logging or debugging.

Templates

String.format('Hello {0}, welcome to {1}', new List<Object>{'Alice', 'Salesforce'});
// 'Hello Alice, welcome to Salesforce'

String.format('Order #{0} amount {1}', new List<Object>{12345, 99.99});
// 'Order #12345 amount 99.99'

Encoding

EncodingUtil.urlEncode('hello world', 'UTF-8');     // 'hello+world'
EncodingUtil.urlDecode('hello%20world', 'UTF-8');   // 'hello world'
EncodingUtil.base64Encode(Blob.valueOf('hi'));      // 'aGk='

SOQL injection protection (critical)

When building soql-in-loops-security-review-impact-for-managed-packages/" class="auto-link">dynamic SOQL with user input, ALWAYS escape:

// SAFE — escape user input
String safeName = String.escapeSingleQuotes(userInput);
String query = 'SELECT Id FROM Account WHERE Name LIKE \'%' + safeName + '%\'';
List<Account> results = Database.query(query);

// SAFER — bind variables when possible (no manual escape needed)
List<Account> results = [SELECT Id FROM Account WHERE Name LIKE :('%' + userInput + '%')];

escapeSingleQuotes prefixes every ' with a \. Without it, a malicious input like ' OR Name LIKE '% lets an attacker exfiltrate data. This is a class of bug audited in every Salesforce security review — get it right.

Common mistakes

  • if (myStr == '') after a SOQL. Salesforce never returns empty strings — fields are either null or have content. Use String.isBlank to handle both cases.
  • String concatenation in a loop. Slow and allocates many garbage objects. Use String.join.
  • Forgetting escapeSingleQuotes on dynamic SOQL. Every code review's #1 finding.
  • Using .equals('foo') on a possibly-null reference. Throws NPE. Use 'foo'.equals(myStr) or String.isNotBlank(myStr) && myStr.equals('foo').
  • .toString() on a possibly-null SObject field. Same NPE. Use String.valueOf(rec.field) — it's null-safe and returns 'null' as a literal.

Quick cheat sheet

Need Method
Null-or-empty check String.isBlank(s)
Split CSV s.split(',')
Build CSV String.join(list, ',')
Substring search s.contains('x')
Replace pattern s.replaceAll('regex', 'new')
Format template String.format('hi {0}', new List<Object>{name})
Convert anything to String String.valueOf(x)
Escape for dynamic SOQL String.escapeSingleQuotes(input)
Case-insensitive equals s.equalsIgnoreCase(other)
Trim whitespace s.trim()

The Apex String class is one of those topics where 90% of real code uses 10% of the methods. Master the ones above and you'll handle every text manipulation case I've seen in 12 years of Salesforce projects.

Frequently asked questions

What is the Apex String class?

The Apex String class is the system class that wraps every Apex String value, providing instance methods (myStr.toUpperCase(), myStr.contains('X')) and static utility methods (String.valueOf(123), String.format()) for text manipulation. Strings in Apex are immutable — every method that 'modifies' a string actually returns a new one.

What are the most useful Apex String methods?

The everyday ones: split() for parsing CSVs, join() for building delimited strings, contains() / startsWith() / endsWith() for substring checks, trim() / replaceAll() for cleanup, format() for templated output, valueOf() for safe conversion from any type, escapeSingleQuotes() for SOQL injection protection, and isBlank() / isNotBlank() for null-safe emptiness checks.

How do I check if a String is null or empty in Apex?

Use String.isBlank(myStr) — it returns true if the string is null, empty, or contains only whitespace. The inverse is String.isNotBlank(). For pure null check, just compare: if (myStr == null). For empty without null check, use myStr == '' but only after confirming non-null. isBlank is the safest default.

What is the difference between String.format and string concatenation in Apex?

String.format(template, args) substitutes positional placeholders {0}, {1}, etc. — useful for translatable strings and message templates. Concatenation ('Hello ' + name) is faster for simple cases. For more than 3 inserts or anything user-facing, use format. For loops, build a List<String> and use String.join() rather than concatenating in a loop (which allocates new strings each iteration).

How do I escape single quotes in Apex SOQL?

Use String.escapeSingleQuotes(input) on any user-supplied string before splicing into a dynamic SOQL query. It prefixes every single quote with a backslash, preventing SOQL injection: String safe = String.escapeSingleQuotes(userInput); query = 'SELECT Id FROM Account WHERE Name = \'' + safe + '\''. For non-dynamic SOQL with bind variables (= :someVar), Salesforce handles escaping automatically — only dynamic Database.query needs manual escaping.

Are Apex Strings case-sensitive?

Yes — by default. 'Apple' != 'apple'. For case-insensitive comparison, use equalsIgnoreCase(): 'Apple'.equalsIgnoreCase('APPLE') returns true. Other case-insensitive variants: containsIgnoreCase, startsWithIgnoreCase, endsWithIgnoreCase. Or normalize both sides with toUpperCase() / toLowerCase() before comparing.

How do I split a String in Apex?

Use split(regex). For a comma-separated value: List<String> parts = 'a,b,c'.split(','). For a regex: 'a-b_c'.split('[-_]'). split() returns a List<String>. To handle empty strings between delimiters, use split(regex, limit) — limit of -1 keeps all empty trailing strings, while default limit drops them.

Newsletter

One email every Tuesday

New guides, tool updates, and the release-note changes that break things.

No spam. Unsubscribe in one click.

Comments

Loading comments...

Leave a Comment