表达式是由变量、运算符和方法调用组成的构造,这些变量、运算符和方法调用 计算结果为单个值。
- 表达式
是由变量、运算符和方法调用组成的构造,其计算结果为单个值。 - 表达式运算符 表达式可以使用运算符
相互连接以创建复合表达式。 - 安全导航运算符 使用安全导航运算符
() 替换对 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.b
a?.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数字形成类型的层次结构。较低数值类型的变量始终可以是 分配给更高的类型,而不进行显式转换。以下是 数字,从低到高:
- 整数
- 长
- 双
- 十进制
注意
一旦将值从较低类型的数字传递到较高类型的数字 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;