Safe Navigation Operator
安全的导航操作符 (?.
) 用于避免 NullPointerException
,并且来自 Groovy 语言。通常,当你拥有指向对象的引用时,在访问该对象的属性或方法之前,你可能需要验证该对象未 null
。为了避免这种情况,安全的导航操作符将返回特殊 null 安全操作的 null
,而不是抛出异常。
The safe navigation operator (?.
) is used to avoid a NullPointerException
and comes
from the Groovy
language. Typically, when you have a reference to an object, you might need to verify
that it is not null
before accessing methods or properties of the object. To avoid
this, the safe navigation operator returns null
for the particular null-safe operation
instead of throwing an exception.
当安全导航运算符对于复合表达式中某个特定空安全操作评估为 null
时,该复合表达式的剩余部分仍将被评估。
When the safe navigation operator evaluates to null
for a particular null-safe
operation within a compound expression, the remainder of the compound expression will
still be evaluated.
有关详细信息,请参阅 Null-safe Operations in Compound Expressions。
See Null-safe Operations in Compound Expressions for details.
Safe Property and Method Access
以下示例演示如何对属性访问使用安全导航运算符(?.
)。
The following example shows how to use the safe navigation operator for property access
(?.
).
- Java
-
ExpressionParser parser = new SpelExpressionParser(); EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build(); Inventor tesla = new Inventor("Nikola Tesla", "Serbian"); tesla.setPlaceOfBirth(new PlaceOfBirth("Smiljan")); // evaluates to "Smiljan" String city = parser.parseExpression("placeOfBirth?.city") (1) .getValue(context, tesla, String.class); tesla.setPlaceOfBirth(null); // evaluates to null - does not throw NullPointerException city = parser.parseExpression("placeOfBirth?.city") (2) .getValue(context, tesla, String.class);
1 | Use safe navigation operator on non-null placeOfBirth property |
2 | Use safe navigation operator on null placeOfBirth property
|
3 | Use safe navigation operator on non-null placeOfBirth property |
4 | Use safe navigation operator on null placeOfBirth property |
安全导航运算符也适用于对对象上的方法调用。 The safe navigation operator also applies to method invocations on an object. 例如,如果在上下文中未配置 For example, the expression |
Safe Index Access
自 Spring Framework 6.2 起,Spring 表达式语言支持对以下类型结构使用安全导航进行索引。
Since Spring Framework 6.2, the Spring Expression Language supports safe navigation for indexing into the following types of structures.
以下示例显示如何使用安全导航运算符对列表进行索引 (?.[]
)。
The following example shows how to use the safe navigation operator for indexing into
a list (?.[]
).
- Java
-
ExpressionParser parser = new SpelExpressionParser(); IEEE society = new IEEE(); EvaluationContext context = new StandardEvaluationContext(society); // evaluates to Inventor("Nikola Tesla") Inventor inventor = parser.parseExpression("members?.[0]") (1) .getValue(context, Inventor.class); society.members = null; // evaluates to null - does not throw an exception inventor = parser.parseExpression("members?.[0]") (2) .getValue(context, Inventor.class);
1 | Use null-safe index operator on a non-null members list |
2 | Use null-safe index operator on a null members list
|
3 | Use null-safe index operator on a non-null members list |
4 | Use null-safe index operator on a null members list |
Safe Collection Selection and Projection
Spring 表达式语言通过以下运算符支持集合选择和集合投影的安全导航。
The Spring Expression Language supports safe navigation for collection selection and collection projection via the following operators.
-
null-safe selection:
?.?
-
null-safe select first:
?.^
-
null-safe select last:
?.$
-
null-safe projection:
?.!
以下示例演示如何对集合选择使用安全导航运算符(?.?
)。
The following example shows how to use the safe navigation operator for collection
selection (?.?
).
- Java
-
ExpressionParser parser = new SpelExpressionParser(); IEEE society = new IEEE(); StandardEvaluationContext context = new StandardEvaluationContext(society); String expression = "members?.?[nationality == 'Serbian']"; (1) // evaluates to [Inventor("Nikola Tesla")] List<Inventor> list = (List<Inventor>) parser.parseExpression(expression) .getValue(context); society.members = null; // evaluates to null - does not throw a NullPointerException list = (List<Inventor>) parser.parseExpression(expression) .getValue(context);
1 | Use null-safe selection operator on potentially null members list
|
2 | Use null-safe selection operator on potentially null members list |
以下示例演示如何对集合使用“null 安全选择第一个”运算符(?.^
)。
The following example shows how to use the "null-safe select first" operator for
collections (?.^
).
- Java
-
ExpressionParser parser = new SpelExpressionParser(); IEEE society = new IEEE(); StandardEvaluationContext context = new StandardEvaluationContext(society); String expression = "members?.^[nationality == 'Serbian' || nationality == 'Idvor']"; (1) // evaluates to Inventor("Nikola Tesla") Inventor inventor = parser.parseExpression(expression) .getValue(context, Inventor.class); society.members = null; // evaluates to null - does not throw a NullPointerException inventor = parser.parseExpression(expression) .getValue(context, Inventor.class);
1 | Use "null-safe select first" operator on potentially null members list
|
2 | Use "null-safe select first" operator on potentially null members list |
以下示例演示如何对集合使用“null 安全选择最后一个”运算符(?.$
)。
The following example shows how to use the "null-safe select last" operator for
collections (?.$
).
- Java
-
ExpressionParser parser = new SpelExpressionParser(); IEEE society = new IEEE(); StandardEvaluationContext context = new StandardEvaluationContext(society); String expression = "members?.$[nationality == 'Serbian' || nationality == 'Idvor']"; (1) // evaluates to Inventor("Pupin") Inventor inventor = parser.parseExpression(expression) .getValue(context, Inventor.class); society.members = null; // evaluates to null - does not throw a NullPointerException inventor = parser.parseExpression(expression) .getValue(context, Inventor.class);
1 | Use "null-safe select last" operator on potentially null members list
|
2 | Use "null-safe select last" operator on potentially null members list |
以下示例演示如何对集合投影使用安全导航运算符(?.!
)。
The following example shows how to use the safe navigation operator for collection
projection (?.!
).
- Java
-
ExpressionParser parser = new SpelExpressionParser(); IEEE society = new IEEE(); StandardEvaluationContext context = new StandardEvaluationContext(society); // evaluates to ["Smiljan", "Idvor"] List placesOfBirth = parser.parseExpression("members?.![placeOfBirth.city]") (1) .getValue(context, List.class); society.members = null; // evaluates to null - does not throw a NullPointerException placesOfBirth = parser.parseExpression("members?.![placeOfBirth.city]") (2) .getValue(context, List.class);
1 | Use null-safe projection operator on non-null members list |
2 | Use null-safe projection operator on null members list
|
3 | Use null-safe projection operator on non-null members list |
4 | Use null-safe projection operator on null members list |
Null-safe Operations in Compound Expressions
如本部分开头所述,当安全导航运算符对复合表达式中的特定 null 安全操作计算为 null
时,复合表达式的其余部分仍将被计算。这意味着必须在整个复合表达式中应用安全导航运算符,以避免任何不必要的 NullPointerException
。
As mentioned at the beginning of this section, when the safe navigation operator
evaluates to null
for a particular null-safe operation within a compound expression,
the remainder of the compound expression will still be evaluated. This means that the
safe navigation operator must be applied throughout a compound expression in order to
avoid any unwanted NullPointerException
.
给定表达式 #person?.address.city
,如果 #person
为 null
,则安全导航运算符(?.
)确保在尝试访问 #person
的 address
属性时不会引发异常。但是,由于 #person?.address
计算为 null
,因此在尝试访问 null
的 city
属性时将引发 NullPointerException
。为了解决此问题,可以在复合表达式中应用 null 安全导航,如 #person?.address?.city
。如果 #person
或 #person?.address
计算为 null
,则该表达式将安全地计算为 null
。
Given the expression #person?.address.city
, if #person
is null
the safe navigation
operator (?.
) ensures that no exception will be thrown when attempting to access the
address
property of #person
. However, since #person?.address
evaluates to null
, a
NullPointerException
will be thrown when attempting to access the city
property of
null
. To address that, you can apply null-safe navigation throughout the compound
expression as in #person?.address?.city
. That expression will safely evaluate to null
if either #person
or #person?.address
evaluates to null
.
以下示例演示了如何在复合表达式中将“null 安全选择第一个”运算符(?.^
)用于一个集合,同时将 null 安全属性访问(?.
)与之结合起来。如果 members
为 null
,则“null 安全选择第一个”运算符(members?.^[nationality == 'Serbian']
)的结果将评估为 null
,而安全导航运算符(?.name
)的进一步使用可确保整个复合表达式评估为 null
,而不是引发异常。
The following example demonstrates how to use the "null-safe select first" operator
(?.^
) on a collection combined with null-safe property access (?.
) within a compound
expression. If members
is null
, the result of the "null-safe select first" operator
(members?.^[nationality == 'Serbian']
) evaluates to null
, and the additional use of
the safe navigation operator (?.name
) ensures that the entire compound expression
evaluates to null
instead of throwing an exception.
- Java
-
ExpressionParser parser = new SpelExpressionParser(); IEEE society = new IEEE(); StandardEvaluationContext context = new StandardEvaluationContext(society); String expression = "members?.^[nationality == 'Serbian']?.name"; (1) // evaluates to "Nikola Tesla" String name = parser.parseExpression(expression) .getValue(context, String.class); society.members = null; // evaluates to null - does not throw a NullPointerException name = parser.parseExpression(expression) .getValue(context, String.class);
1 | Use "null-safe select first" and null-safe property access operators within compound expression.
|
2 | Use "null-safe select first" and null-safe property access operators within compound expression. |