Apex表达式和运算符

表达式是由变量、运算符和方法调用组成的构造,这些变量、运算符和方法调用 计算结果为单个值。

  • 表达式
    是由变量、运算符和方法调用组成的构造,其计算结果为单个值。
  • 表达式运算符 表达式可以使用运算符
    相互连接以创建复合表达式。
  • 安全导航运算符 使用安全导航运算符
    () 替换对 null 引用的显式顺序检查。此运算符使尝试对 null 值进行操作的表达式短路,并返回 null 而不是引发 NullPointerException。?.
  • 运算符优先级
    运算符根据规则按顺序进行解释。
  • 注释
    Apex 代码支持单行和多行注释。

表达式

表达式是由变量、运算符和方法调用组成的构造 计算结果为单个值。

在 Apex 中,表达式始终是以下类型之一:

  • 文字表达式。例如:1 + 1
  • 新的 sObject、Apex 对象、列表、集或映射。为 例:new Account(<field_initializers>) new Integer[<n>] new Account[]{<elements>} new List<Account>() new Set<String>{} new Map<String, Integer>() new myRenamingClass(string oldName, string newName)
  • 任何可以充当赋值运算符左侧的值(L 值), 包括变量、一维列表位置以及大多数 sObject 或 Apex 对象 字段引用。例如:Integer i myList[3] myContact.name myRenamingClass.oldName
  • 任何不是 L 值的 sObject 字段引用,包括:
    • 列表中 sObject 的 ID(请参阅列表)
    • 与 sObject 关联的一组子记录(例如,一组 与特定帐户关联的联系人)。这种类型的表达式 生成查询结果,与 SOQL 和 SOSL 查询非常相似。
  • 用方括号括起来的 SOQL 或 SOSL 查询,允许动态 在 Apex 中评估。为 例:Account[] aa = [SELECT Id, Name FROM Account WHERE Name ='Acme']; Integer i = [SELECT COUNT() FROM Contact WHERE LastName ='Weissman']; List<List<SObject>> searchList = [FIND 'map*' IN ALL FIELDS RETURNING Account (Id, Name), Contact, Opportunity, Lead];为 信息,请参阅 SOQL 和 SOSL 查询。
  • 静态方法或实例方法调用。为 例:System.assert(true) myRenamingClass.replaceNames() changePoint(new Point(x, y));

表达式运算符

表达式可以使用运算符相互连接以创建复合 表达 式。

Apex 支持以下运算符:

算子 语法 描述
= x = y 赋值运算符(右关联)。将 的值分配给 L 值。的数据类型必须与 的数据类型匹配,并且不能是 。yxxynull
+= x += y 加法赋值运算符(右关联)。添加 到原始值的值 的值,然后重新赋值 的新值。有关其他信息,请参阅。 而且不可能.yxx+xynull
*= x *= y 乘法赋值运算符(右关联)。 将 with 的值相乘 和 的原始值 然后将新值重新分配给 。yxx注意x并且必须是整数或 双打或组合。yx而且不可能.ynull
-= x -= y 减法赋值运算符(右关联)。减去 的值从 和 的原始值 将新值重新分配给 。yxx注意x并且必须是整数或双精度 或两者兼而有之。yx而且不可能.ynull
/= x /= y 除法赋值运算符(右关联)。除以 的原始值与 的值,然后重新赋值 的新值。xyx注意x并且必须是整数或双精度 或两者兼而有之。yx而且不可能.ynull
|= x |= y OR 赋值运算符(右关联)。如果 、 布尔值和 布尔值均为 false,则保持 false。否则,将赋值为 真。 而且不可能.xyxxxynull
&= x &= y AND 赋值运算符(右关联)。如果 、 布尔值和 布尔值都为 true,则保持为 true。否则,将赋值为 假。 而且不可能.xyxxxynull
<<= x <<= y 按位左移赋值运算符。将每个位向左移动一位,以便高阶位 丢失,新的右位设置为 0。此值为 重新分配给 。xyx
>>= x >>= y 按位右移有符号赋值运算符。每个班次 逐位向右插入,以便 低阶位丢失,新的左位设置为 0 表示正数 的值为 和 1 为负数 的值。此值为 重新分配给 。xyyyx
>>>= x >>>= y 按位右移无符号赋值运算符。每个班次 逐位向右插入,以便 低阶位将丢失,新的左位将全部设置为 0 的值。此值为 重新分配给 。xyyx
? : x ? y : z 三元运算符(右关联)。此运算符充当 if-then-else 语句的简写。如果 ,布尔值为 true,则为结果。否则就是结果。xyz注意x不可能.null
&& x && y AND 逻辑运算符(左关联)。如果 、 布尔值和 布尔值均为 true,则 表达式的计算结果为 true。否则,表达式的计算结果为 假。xy注意:&&有 优先于||该算子表现出短路行为,这 手段是 仅当为 true 时才计算。yxx而且不可能.ynull
|| x || y OR 逻辑运算符(左关联)。如果 、布尔值和布尔值均为 false,则 表达式的计算结果为 false。否则,表达式的计算结果为 真。xy注意:&&有 优先于||该算子表现出短路行为,这 手段是 仅当为 false 时才计算。yxx而且不可能.ynull
== x == y 相等运算符。如果 的值等于 的值,则表达式的计算结果为 真。否则,表达式的计算结果为 false。xy注意与 Java 不同,在 Apex 比较对象值相等性而不是引用相等性, 用户定义类型除外。因此:==对于 sObjects 和 sObject 数组,执行深度 在返回其之前检查所有 sObject 字段值 结果。 同样 用于集合和内置 Apex 对象。==对于记录,每个字段必须具有相同的值才能进行评估 到真。==x或者可以是字面上的。ynull任何两个值的比较都不能产生 。nullSOQL 和 SOSL 用于它们的相等运算符,而不是 .虽然 Apex 和 SOQL 和 SOSL 是紧密相连的,这种不幸的语法 之所以存在差异,是因为大多数现代语言都用于赋值和 平等。Apex 的设计者认为它更有价值 保持这种范式,而不是强迫开发人员学习 新的赋值运算符。因此,Apex 开发人员必须 用于平等 在 Apex 代码的主体中进行测试,并在 SOQL 中进行相等性测试 和 SOSL 查询。=========使用 is 进行字符串比较 不区分大小写,并根据 上下文用户的区域设置==ID 比较使用区分大小写,不区分大小写 区分 15 个字符和 18 个字符 格式==用户定义的类型通过引用进行比较,其中 表示两个对象只有在它们 引用内存中的相同位置。您可以 通过以下方式覆盖此默认比较行为 提供和方法 来比较对象值。equalshashCode
=== x === y 完全相等运算符。If 和引用 表达式在内存中计算结果为 true 的位置完全相同。 否则,表达式的计算结果为 false。xy
< x < y 小于操作员。如果小于 , 表达式的计算结果为 true。否则,表达式的计算结果为 假。xy注意与其他数据库存储过程不同,Apex 没有 支持三态布尔逻辑和任何两个值的比较都不能产生 。null如果 或 等于 并且是整数, Doubles、Dates 或 Datetimes,则表达式为 false。xynull非字符串或 ID 值始终较大 比一个值。nullnull如果 和 是 ID, 它们必须引用相同类型的对象。否则 运行时错误结果。xy如果 or 是 ID 和 other value 是 String,则验证 String 值 并被视为 ID。xyx而且不可能 布尔 值。y两个字符串的比较是根据 上下文用户的区域设置,并且不区分大小写。
> x > y 大于运算符。如果大于 ,则表达式的计算结果为 true。否则, 表达式的计算结果为 false。xy注意任何两个值的比较都不能产生 。null如果 或 等于 并且是整数, Doubles、Dates 或 Datetimes,则表达式为 false。xynull非字符串 或 ID 值始终大于某个值。nullnull如果 和 是 ID,则它们必须 引用相同类型的对象。否则为运行时错误 结果。xy如果 or 是 ID 和 other value 是 String,对 String 值进行验证,并且 视为 ID。xyx而且不可能 布尔 值。y两个字符串的比较是根据 上下文用户的区域设置,并且不区分大小写。
<= x <= y 小于或等于运算符。如果小于或等于 ,则表达式的计算结果为 真。否则,表达式的计算结果为 false。xyNoteThe comparison of any two values can never result in .nullIf or equal and are Integers, Doubles, Dates, or Datetimes, the expression is false.xynullA non- String or ID value is always greater than a value.nullnullIf and are IDs, they must reference the same type of object. Otherwise a runtime error results.xy如果 or 是 ID 和 other value 是 String,对 String 值进行验证,并且 视为 ID。xyx而且不可能 布尔 值。y两个字符串的比较是根据 上下文用户的区域设置,并且不区分大小写。
>= x >= y 大于或等于运算符。如果大于或等于 ,则表达式的计算结果 到真。否则,表达式的计算结果为 false。xy注意任何两个值的比较都不能产生 。null如果 或 等于 并且是整数, Doubles、Dates 或 Datetimes,则表达式为 false。xynull非字符串 或 ID 值始终大于某个值。nullnull如果 和 是 ID,则它们必须 引用相同类型的对象。否则为运行时错误 结果。xy如果 or 是 ID 和 other value 是 String,对 String 值进行验证,并且 视为 ID。xyx而且不可能 布尔 值。y两个字符串的比较是根据 上下文用户的区域设置,并且不区分大小写。
!= x != y 不等式运算符。如果 的值不等于 的值 ,则表达式的计算结果为 到真。否则,表达式的计算结果为 false。xy注意字符串比较使用不区分大小写!=与 Java 不同,在 Apex 比较对象值相等性而不是引用相等性, 用户定义类型除外。!=对于 sObjects 和 sObject 数组,执行深度 在返回其之前检查所有 sObject 字段值 结果。!=对于记录,如果记录具有不同的值,则计算结果为 true 任何字段。!=用户定义的类型通过引用进行比较,这意味着 只有当两个对象引用时,它们才不同 内存中的不同位置。您可以覆盖此默认值 通过提供 和 方法来比较行为 类来比较对象值。equalshashCodex或者可以是字面上的。ynull任何两个值的比较都不能产生 。null
!== x !== y 精确不等式运算符。如果和不 引用内存中完全相同的位置,表达式的计算结果为 真。否则,表达式的计算结果为 false。xy
+ x + y 加法运算符。根据以下规则将 的值添加到 的值中:xy如果 和 是整数或双精度, 运算符将 的值与 的值相加。如果使用 Double,则结果为 双。xyxy如果是 Date 并且是 Integer, 返回按指定数字递增的新日期 天。xyIf 是 Datetime 并且是 Integer 或 Double,返回一个新的 Date,该日期按指定的 天数,小数部分对应于 一天的一部分。xyIf 是 String 并且是 String 或 任何其他类型的非参数,都连接到 的末尾。xynullyx
x – y 减法运算符。根据以下规则从 的值中减去 的值:yx如果 和 是整数或双精度, 运算符从 的值中减去 的值。如果使用 Double,则 结果是 Double。xyyx如果是 Date 并且是 Integer, 返回一个按指定数字递减的新 Date 天。xyIf 是 Datetime 并且是 Integer 或 Double,返回一个减去指定值的新日期 天数,小数部分对应于 一天的一部分。xy
* x * y 乘法运算符。将 、 整数或 Double 与 、 另一个 Integer 或 相乘 双。如果使用 double,则结果为 double。xy
/ x / y 部门操作员。将一个整数或双精度除以另一个整数或双精度。如果 double,结果是 Double。xy
! !x 逻辑补码运算符。反转布尔值,因此 真变成假,假变成真。
-x 一元否定运算符。将 、 整数或双精度的值乘以 -1。这 正等价物也是 语法上有效,但没有数学效果。x+
++ x++++x 增量运算符。将 1 添加到数值类型的变量 的值上。如果 前缀 (),表达式 增量后的计算结果为 x 的值。如果后缀为 (),则表达式的计算结果为 增量前的 x 值。x++xx++
x––x 递减运算符。从 的值中减去 1,这是一个数值类型的变量。如果 前缀 (),表达式 计算结果为递减后的 x 值。如果后缀为 (),则表达式的计算结果为 递减前的 x 值。x–xx–
& x & y 按位 AND 运算符。AND 将每个位 in 与相应的位 in 一起,使结果位为 如果两个位都设置为 1,则设置为 1。xy
| x | y 按位 OR 运算符。OR将每个位输入到相应的位,以便结果位为 如果至少有一个位设置为 1,则设置为 1。xy
^ x ^ y 按位独占 OR 运算符。每个位的独占 OR 与相应的 位,以便结果位 如果恰好其中一个位设置为 1,而另一个位设置为 1,则设置为 1 设置为 0。xy
^= x ^= y 按位独占 OR 运算符。每个位的独占 OR 与相应的 位,以便结果位 如果恰好其中一个位设置为 1,而另一个位设置为 1,则设置为 1 设置为 0。将独占 OR 运算的结果分配给 。xyx
<< x << y 按位左移运算符。将每个位向左移动一位,以便高阶位 丢失,新的右位设置为 0。xy
>> x >> y 按位右移有符号运算符。将每个位向右移动一位,以便低阶位 丢失,新的左位设置为 0 表示正值,1 表示负值 之。xyyy
>>> x >>> y 按位右移无符号运算符。将每个位向右移动一位,以便低阶位 丢失,并且 的所有值的新左位都设置为 0。xyy
~ ~x 按位 Not 或 Complement 运算符。切换每个二进制数字 的 ,将 0 转换为 1 和 1 更改为 0。布尔值从 to 和 vice 转换 反之亦然。xTrueFalse
() (x) 括号。提升表达式的优先级,以便首先在 复合表达式。x
?. x?.y 安全导航操作员。短路表达式 尝试对 null 值进行操作,并返回 null 而不是抛出 一个 NullPointerException。如果链表达式的左侧 计算结果为 null,则链表达式的右侧不是 评价。

安全导航操作员

使用安全导航运算符 () 替换对 null 引用的显式顺序检查。这 运算符短路尝试对 null 值进行操作并返回的表达式 null 而不是抛出 NullPointerException。?.

重要

在可能的情况下,我们更改了非包容性条款,以符合我们的 平等的公司价值观。我们保留了某些条款,以避免对 客户实施。

如果链表达式的左侧计算结果为 null,则右侧的计算结果为 null 未进行评估。在方法、变量和属性链接中使用安全导航运算符 ()。部分 未计算的表达式可以包括变量引用、方法引用、 或数组表达式。?.

注意

所有 Apex 类型都可以隐式为 null,并且可以保存从 算子。

例子

  • 此示例首先计算 ,并且 如果为 null,则返回 null。否则, 返回值为 。aaa.ba?.b // Evaluates to: a == null ? null : a.b
  • 如果计算结果为 null,则此示例返回 null。如果没有 计算结果为 null 并返回 null,则此表达式将抛出一个 NullPointerException。a[x]a[x]aMethod()a[x]?.aMethod().aField // Evaluates to null if a[x] == null
  • 如果计算结果为 null,则此示例返回 null。a[x].aMethod()a[x].aMethod()?.aField
  • 此示例指示表达式的类型是否相同,无论 在表达式中使用安全导航运算符,或者 不。Integer x = anObject?.anIntegerField; // The expression is of type Integer because the field is of type Integer
  • 此示例演示一个语句,该语句替换了检查 null 值。// Previous code checking for nulls String profileUrl = null; if (user.getProfileUrl() != null) { profileUrl = user.getProfileUrl().toExternalForm(); }// New code using the safe navigation operator String profileUrl = user.getProfileUrl()?.toExternalForm();
  • 此示例演示使用安全导航运算符的单行 SOQL 查询。// Previous code checking for nulls results = [SELECT Name FROM Account WHERE Id = :accId]; if (results.size() == 0) { // Account was deleted return null; } return results[0].Name;// New code using the safe navigation operator return [SELECT Name FROM Account WHERE Id = :accId]?.Name;
允许的用例 更多信息
方法、变量或参数链 aObject?.aMethod(); 可用作顶级语句。
使用括号,例如在强制转换中。 ((T)a1?.b1)?.c1() 运算符将方法链跳过到第一次关闭 括号。通过在括号后添加运算符,代码 保护整个表达式。如果运算符在其他地方使用, 而不是在括号之后,整个强制转换表达式不是 be 保障。例如,行为//Incorrect use of safe navigation operator ((T)a1?.b1).c1()相当于:T ref = null; if (a1 != null) { ref = (T)a1.b1; } result = ref.c1();
SObject 链接 String s = contact.Account?.BillingCity; 当关系为 零。该行为等效于 。String s = contact.Account.BillingCity
SOQL 查询 String s = [SELECT LastName FROM Contact]?.LastName; 如果 SOQL 查询未返回任何对象,则表达式 计算结果为 null。该行为等效于:List<Contact> contacts = [SELECT LastName FROM Contact]; String s; if (contacts.size() == 0) { s = null; // New behavior when using Safe Navigation. Earlier, this would throw an exception. } else if (contacts.size() == 1) { s = contacts.get(0).LastName; } else { // contacts.size() > 1 throw new QueryException(...); }

在某些情况下,您不能使用安全导航运算符。尝试使用 运算符在编译过程中会导致错误:

  • 带点的类型和静态表达式。例如:
    • 命名空间
    • {命名空间}。{类}
    • 触发器.new
    • Flow.interview。{流名称}
    • {类型}.class
  • 静态变量访问、方法调用和表达式。例如:
    • AClass.AStaticMethodCall()
    • AClass.AStaticVariable
    • String.format(‘{0}’, ‘hello world’)
    • Page.{pageName}
  • Assignable expressions. For example:
    • foo?.bar = 42;
    • ++foo?.bar;
  • SOQL 绑定表达式。为 例:class X { public String query = 'xyz';} X x = new X(); List<Account> accounts = [SELECT Name FROM Account WHERE Name = :X?.query] List<List<SObject>> moreAccounts = [FIND :X?.query IN ALL FIELDS RETURNING Account(Name)];
  • 使用 SObject 标量 领域。例如:addError()Contact c; c.LastName?.addError('The field must have a value');注意你 可以将运算符与 SObjects 一起使用,包括查找和主从细节 领域。addError()

运算符优先级

运算符根据规则按顺序解释。

Apex 使用以下运算符优先级规则:

优先 运营商 描述
1 {} () ++ — 分组和前缀递增和递减
2 ~ ! -x +x (type) new 一元运算符、加法运算符、类型转换和对象 创造
3 * / 乘法和除法
4 + – 加法和减法
5 << >> >>> 轮班操作员
6 < <= > >= instanceof 大于和小于比较、参考测试
7 == != 比较:相等和不相等
8 & 按位 AND
9 ^ 按位异或
10 | 按位 OR
11 && 逻辑 AND
12 || 逻辑 OR
13 = += -= *= /= &= <<= >>= >>>=

注释

Apex 代码支持单行和多行注释。

  • 要创建单行注释,请使用 . 解析器将忽略 右侧同一行上的所有字符。为 例:////Integer i = 1; // This comment is ignored by the parser
  • 若要创建多行注释,请使用 和 来分隔开头和结尾 的评论块。为 例:/**/Integer i = 1; /* This comment can wrap over multiple lines without getting interpreted by the parser. */

赋值语句

赋值语句是将值放入 变量。赋值语句通常采用以下两种方式之一 形式:

[LValue] = [new_value_expression];
[LValue] = [[inline_soql_query]];

在上面的表格中,代表任何 可以放置在赋值运算符左侧的表达式。这些包括:

[LValue]

  • 一个简单的变量。为 例:Integer i = 1; Account a = new Account(); Account[] accts = [SELECT Id FROM Account];
  • 取消引用的列表元素。为 例:ints[0] = 1; accts[0].Name = 'Acme';
  • 上下文用户有权编辑的 sObject 字段引用。为 例:Account a = new Account(Name = 'Acme', BillingCity = 'San Francisco'); // IDs cannot be set prior to an insert call // a.Id = '00300000003T2PGAA0'; // Instead, insert the record. The system automatically assigns it an ID. insert a; // Fields also must be writable for the context user // a.CreatedDate = System.today(); This code is invalid because // createdDate is read-only! // Since the account a has been inserted, it is now possible to // create a new contact that is related to it Contact c = new Contact(LastName = 'Roth', Account = a); // Notice that you can write to the account name directly through the contact c.Account.Name = 'salesforce.com';

赋值始终通过引用完成。为 例:

Account a = new Account();
Account b;
Account[] c = new Account[]{};
a.Name = 'Acme';
b = a;         
c.add(a);      

// These asserts should now be true. You can reference the data
// originally allocated to account a through account b and account list c.
System.assertEquals(b.Name, 'Acme');          
System.assertEquals(c[0].Name, 'Acme');

同样,两个列表可以指向内存中的相同值。为 例:

Account[] a = new Account[]{new Account()};
Account[] b = a;
a[0].Name = 'Acme';
System.assert(b[0].Name == 'Acme');

除了 之外,其他有效分配 运算符包括 、 、 、 、 和 。请参阅表达式 运算符=+=*=/=|=&=++

转换规则

通常,Apex 要求您显式将一种数据类型转换为另一种数据类型。为 例如,Integer 数据类型的变量不能隐式转换为 String。你 必须使用该方法。但是,一些 数据类型可以隐式转换,而无需使用方法。

string.format数字形成类型的层次结构。较低数值类型的变量始终可以是 分配给更高的类型,而不进行显式转换。以下是 数字,从低到高:

  1. 整数
  2. 十进制

注意

一旦将值从较低类型的数字传递到较高类型的数字 type,则该值将转换为更高类型的数字。

请注意,层次结构和隐式转换与数字的 Java 层次结构不同, 其中使用基本接口号,并且从不进行隐式对象转换 允许。除数字外,还可以隐式转换其他数据类型。以下规则适用:

  • ID 始终可以分配给字符串。
  • 可以将字符串分配给 ID。但是,在运行时,该值将检查为 确保它是合法的 ID。如果不是,则运行时异常是 扔。
  • 关键字始终可以是 用于测试字符串是否为 ID。instanceOf

数据类型的其他注意事项

数值的数据类型数值表示整数值,除非它们附加了 L a Long 或 .0 表示双精度或小数。例如,表达式声明一个 Long 名为 d 的变量并将其赋值给一个整数数值 (123),即 隐式转换为 Long。右侧的整数值为 在整数范围内,赋值成功。但是,如果 右侧的数值超出了 整数,则会出现编译错误。在这种情况下,解决方案是 将 L 追加到数值,以便它表示具有 范围更广,如以下示例所示:。Long d = 123;Long d = 2147483648L;数据类型值溢出产生大于最大值的算术计算 电流类型被称为溢出。例如,产生一个 值为 –2147483648,因为 2147483647 是 整数,因此向其添加 1 会将值包装到最小的负数 整数的值为 –2147483648。Integer i = 2147483647 + 1;如果算术计算生成的结果大于最大值 对于当前类型,最终结果将不正确,因为计算出的 大于最大值的值将溢出。例如, 表达式会导致不正确的结果,因为 右侧整数的乘积大于最大值 整数值,它们会溢出。因此,最终产品不是 期待一个。您可以通过确保数值的类型来避免这种情况 或者您在算术运算中使用的变量足够大,可以容纳 结果。在此示例中,将 L 追加到数值以使其成为 Long 所以中间产品也会很长,不会发生溢出。 以下示例演示如何正确计算 一年中的毫秒乘以长数字 值。Long MillsPerYear = 365 * 24 * 60 * 60 * 1000;

Long MillsPerYear = 365L * 24L * 60L * 60L * 1000L;
Long ExpectedValue = 31536000000L;
System.assertEquals(MillsPerYear, ExpectedValue);

分部分数损失将数值 Integer 或 Long 值相除时,将 结果(如果有)在执行任何隐式转换为 双精度或十进制。例如,返回 1.0,因为实际结果 (1.666…) 是 整数,在隐式转换为 Double 之前四舍五入为 1。 要保留小数值,请确保使用 Double 或 除法中的十进制数值。例如,返回 1.66666666666666667,因为 5.0 和 3.0 表示 Double 值,其中 结果商也是双精度,没有小数值是 失去。Double d = 5/3;Double d = 5.0/3.0;