6.1 Variables, Constants & Apex Data Types

Key Takeaways

  • Apex is a strongly typed, Java-like language: every variable has a declared type, and the compiler rejects mismatched assignments
  • Use final for constants; prefer Decimal over Double for money and precise currency math
  • Primitive types include Integer, Long, Double, Decimal, Boolean, String, Date, Datetime, Time, Id, and Blob
  • sObject types (Account, Contact, custom objects) are first-class values you can construct, query, and DML
  • Uninitialized variables are null; null dereference throws NullPointerException—guard before calling methods on possibly null references
Last updated: August 2026

6.1 Variables, Constants & Apex Data Types

Quick Answer: Apex is a strongly typed, object-oriented language similar to Java. You declare variables with an explicit type, mark unchanging values with final, prefer Decimal for money, and treat null carefully because method calls on null throw NullPointerException. sObject types (standard and custom) are first-class values alongside primitives.

This section is foundation for Process Automation and Logic on Platform Developer I. Later chapters assume you can read type signatures, choose Decimal vs Double, and reason about null and conversion behavior under exam scenarios.

Declaring Variables and Constants

Declare a variable with a type, optional initializer, and a name that starts with a letter or underscore:

Integer quantity = 10;
String status = 'Open';
Boolean isActive;
Account acct = new Account(Name = 'Acme');

Uninitialized locals default to null (including numeric types). That is different from some languages that zero-initialize numbers. Writing Integer n; System.debug(n + 1); fails at runtime with a null-related error because you cannot unbox null for arithmetic without a non-null value.

Use final for values that must not be reassigned after initialization:

final Integer MAX_RETRIES = 3;
final String DEFAULT_STATUS = 'New';

final variables can be assigned once (including constructor or declaration). Attempting a second assignment does not compile. Class-level static final constants are common for limit thresholds, default statuses, and configuration keys that should not drift across methods.

Exam trap: final does not make an sObject’s field values immutable. You can still change acct.Name on a final Account acct reference; you simply cannot point acct at a different Account instance.

Primitive Types You Must Know

TypeRoleExam notes
Integer32-bit whole numberOverflow wraps; use for counts and small IDs
Long64-bit whole numberLarger ranges; suffix L in literals (100L)
DoubleIEEE floating pointApproximate; not for currency
DecimalArbitrary-precision decimalMoney, rates, tax—default for currency fields
Booleantrue / false / nullThree-state when uninitialized
StringUnicode textImmutable; use == for value equality
DateCalendar date (no time)Date.today(), Date.newInstance(y,m,d)
DatetimeDate + time + timezone contextDatetime.now(), GMT storage considerations
TimeTime of day onlyLess common on exam but valid
Id15- or 18-character Salesforce IDCase-sensitive 15-char; 18-char is case-insensitive
BlobBinary dataAttachments, callout bodies, Crypto

String equality: Use == for content comparison in Apex (unlike Java’s reference ==). Use === only when you specifically care about reference identity for objects.

Id type: Prefer Id over String for record identifiers so invalid ID formats fail early and APIs stay clear. 15-character IDs are case-sensitive; 18-character IDs add a checksum suffix and are safer across case-folding systems.

Decimal for Money (Hard Rule)

Currency and precise arithmetic belong on Decimal, not Double:

Decimal unitPrice = 19.99;
Decimal qty = 3;
Decimal total = unitPrice * qty; // 59.97 exactly as Decimal math

// Currency fields on sObjects are Decimal
Opportunity o = new Opportunity(Amount = 1000.50);

Double is fine for scientific or approximate metrics. Exam scenarios that mention invoices, tax, discounts, or Opportunity Amount almost always expect Decimal (or the field type already is Currency → Decimal in Apex).

Scale and rounding matter when you divide:

Decimal share = 100 / 3;           // Integer division first if both are Integer!
Decimal shareSafe = 100.0 / 3;     // Better: involve Decimal/Double explicitly
Decimal precise = Decimal.valueOf(100).divide(3, 2, RoundingMode.HALF_UP);

Mixing Integer division with money is a classic bug: 100 / 3 is Integer 33, not 33.33. Cast or use Decimal operands before dividing money.

sObject Types

Every standard and custom object is an Apex type. You can:

  • Construct with named parameters: new Contact(LastName = 'Lee', Email = 'lee@example.com')
  • Read/write fields with dot notation: c.Email = 'new@example.com'
  • Hold query results: Account a = [SELECT Id, Name FROM Account LIMIT 1];
  • Use generic SObject when the type is dynamic

Custom objects and fields use __c suffixes: Invoice__c inv = new Invoice__c(Amount__c = 250);.

Generic sObject access uses get / put:

SObject sob = new Account();
sob.put('Name', 'Generic Name');
String name = (String)sob.get('Name');

Prefer concrete types when you know the object; use SObject for frameworks, dynamic SOQL, and reusable utilities.

Type Conversion and Casting

Apex converts some primitives automatically (widening), but many conversions are explicit:

Integer i = 42;
Long l = i;                    // widening OK
String s = String.valueOf(i);  // Integer → String
Integer parsed = Integer.valueOf('42');
Decimal d = Decimal.valueOf('19.99');
Id accountId = (Id)'001000000000001AAA';

Casting sObjects downcasts must match the runtime type or you get a runtime exception:

SObject sob = [SELECT Id, Name FROM Account LIMIT 1];
Account a = (Account)sob; // OK if sob is Account

valueOf methods throw when the string is not parseable—handle or validate input rather than assuming clean data from users or integrations.

Null Behavior and Safe Navigation

Null is a first-class value. Common patterns:

  • Optional fields on queried records may be null
  • Maps return null when a key is missing (map.get(id))
  • Method chains like acct.Owner.Name fail if any segment is null
String ownerName = acct.Owner?.Name; // safe navigation: null if Owner is null
if (acct != null && acct.Name != null) {
    // guarded use
}

Safe navigation (?.) short-circuits to null instead of throwing. It is excellent for display and defensive coding. Do not use it to hide logic errors when a value is required for business rules—fail clearly when data must exist.

Expressions and Operators

Apex supports familiar arithmetic (+ - * /), comparison (== != < > <= >=), logical (&& || !), and ternary (condition ? a : b) operators. String concatenation uses +. Assignment operators (+=, -=) work on numbers and strings as expected.

Boolean short-circuiting applies: in a && b(), b() is not called if a is false—useful when b() would null-dereference.

instanceof checks runtime type:

if (sob instanceof Account) {
    Account a = (Account)sob;
}

Putting It Together for the Exam

When a question shows a snippet, ask:

  1. What is each variable’s type, including null?
  2. Is money on Decimal or accidentally on Double/Integer division?
  3. Will a cast or valueOf throw on bad input?
  4. Does field access assume a non-null relationship?

Mastering these basics prevents missing “easy” items so you can spend time on triggers, bulkification, and governor limits in later chapters.

Test Your Knowledge

A developer needs to store an invoice line total that must remain exact for currency calculations. Which Apex type should they use?

A
B
C
D
Test Your Knowledge

What happens when an Apex local Integer variable is declared without an initializer and then used in arithmetic?

A
B
C
D
Test Your Knowledge

Which statement about the final keyword in Apex is correct?

A
B
C
D