此版本仍在开发中,尚不被认为是稳定的。对于最新的稳定版本,请使用 Spring Framework 6.2.10! |
安全导航操作员
安全导航操作员 (?.
) 用于避免NullPointerException
并来
来自 Groovy 语言。通常,当您有对对象的引用时,您可能需要验证
事实并非如此null
在访问对象的方法或属性之前。避免
此,安全导航运算符返回null
用于特定的空安全作
而不是抛出异常。
当安全导航操作员评估为 有关详细信息,请参阅复合表达式中的空安全作。 |
安全属性和方法访问
以下示例演示如何使用安全导航运算符进行属性访问
(?.
).
-
Java
-
Kotlin
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 | 在非 null 上使用安全导航运算符placeOfBirth 属性 |
2 | 在 null 上使用安全导航运算符placeOfBirth 属性 |
val parser = SpelExpressionParser()
val context = SimpleEvaluationContext.forReadOnlyDataBinding().build()
val tesla = Inventor("Nikola Tesla", "Serbian")
tesla.setPlaceOfBirth(PlaceOfBirth("Smiljan"))
// evaluates to "Smiljan"
var city = parser.parseExpression("placeOfBirth?.city") (1)
.getValue(context, tesla, String::class.java)
tesla.setPlaceOfBirth(null)
// evaluates to null - does not throw NullPointerException
city = parser.parseExpression("placeOfBirth?.city") (2)
.getValue(context, tesla, String::class.java)
1 | 在非 null 上使用安全导航运算符placeOfBirth 属性 |
2 | 在 null 上使用安全导航运算符placeOfBirth 属性 |
安全导航运算符还适用于对象上的方法调用。 例如,表达式 |
安全索引访问
从 Spring Framework 6.2 开始,Spring 表达式语言支持 索引到以下类型的结构中。
以下示例演示如何使用安全导航运算符将索引编入
列表 (?.[]
).
-
Java
-
Kotlin
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 | 对非 null 使用 null 安全索引运算符members 列表 |
2 | 对 null 使用 null 安全索引运算符members 列表 |
val parser = SpelExpressionParser()
val society = IEEE()
val context = StandardEvaluationContext(society)
// evaluates to Inventor("Nikola Tesla")
var inventor = parser.parseExpression("members?.[0]") (1)
.getValue(context, Inventor::class.java)
society.members = null
// evaluates to null - does not throw an exception
inventor = parser.parseExpression("members?.[0]") (2)
.getValue(context, Inventor::class.java)
1 | 对非 null 使用 null 安全索引运算符members 列表 |
2 | 对 null 使用 null 安全索引运算符members 列表 |
安全馆藏选择和投影
-
空安全选择:
?.?
-
空安全选择优先:
?.^
-
空安全选择最后:
?.$
-
空安全投影:
?.!
以下示例演示如何使用安全导航运算符进行收集
选择 (?.?
).
-
Java
-
Kotlin
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 | 对潜在 null 使用 null 安全选择运算符members 列表 |
val parser = SpelExpressionParser()
val society = IEEE()
val context = StandardEvaluationContext(society)
val expression = "members?.?[nationality == 'Serbian']" (1)
// evaluates to [Inventor("Nikola Tesla")]
var list = parser.parseExpression(expression)
.getValue(context) as List<Inventor>
society.members = null
// evaluates to null - does not throw a NullPointerException
list = parser.parseExpression(expression)
.getValue(context) as List<Inventor>
1 | 对潜在 null 使用 null 安全选择运算符members 列表 |
以下示例演示如何使用“空安全优先选择”运算符
集合 (?.^
).
-
Java
-
Kotlin
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 | 对潜在的 null 使用 “null-safe select first” 运算符members 列表 |
val parser = SpelExpressionParser()
val society = IEEE()
val context = StandardEvaluationContext(society)
val expression =
"members?.^[nationality == 'Serbian' || nationality == 'Idvor']" (1)
// evaluates to Inventor("Nikola Tesla")
var inventor = parser.parseExpression(expression)
.getValue(context, Inventor::class.java)
society.members = null
// evaluates to null - does not throw a NullPointerException
inventor = parser.parseExpression(expression)
.getValue(context, Inventor::class.java)
1 | 对潜在的 null 使用 “null-safe select first” 运算符members 列表 |
以下示例演示如何使用“空安全选择最后”运算符
集合 (?.$
).
-
Java
-
Kotlin
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 | 对潜在 null 使用 “null-safe select last” 运算符members 列表 |
val parser = SpelExpressionParser()
val society = IEEE()
val context = StandardEvaluationContext(society)
val expression =
"members?.$[nationality == 'Serbian' || nationality == 'Idvor']" (1)
// evaluates to Inventor("Pupin")
var inventor = parser.parseExpression(expression)
.getValue(context, Inventor::class.java)
society.members = null
// evaluates to null - does not throw a NullPointerException
inventor = parser.parseExpression(expression)
.getValue(context, Inventor::class.java)
1 | 对潜在 null 使用 “null-safe select last” 运算符members 列表 |
以下示例演示如何使用安全导航运算符进行收集
投影 (?.!
).
-
Java
-
Kotlin
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 | 对非空使用空安全投影运算符members 列表 |
2 | 对 null 使用 null 安全投影运算符members 列表 |
val parser = SpelExpressionParser()
val society = IEEE()
val context = StandardEvaluationContext(society)
// evaluates to ["Smiljan", "Idvor"]
var placesOfBirth = parser.parseExpression("members?.![placeOfBirth.city]") (1)
.getValue(context, List::class.java)
society.members = null
// evaluates to null - does not throw a NullPointerException
placesOfBirth = parser.parseExpression("members?.![placeOfBirth.city]") (2)
.getValue(context, List::class.java)
1 | 对非空使用空安全投影运算符members 列表 |
2 | 对 null 使用 null 安全投影运算符members 列表 |
空安全作Optional
从 Spring Framework 7.0 开始,在java.util.Optional
具有透明的展开语义。
具体来说,当空安全运算符应用于空运算符时 Optional
,它将是
视为Optional
是null
,后续作将评估为null
. 但是,如果将空安全运算符应用于非空运算符Optional
这
后续作将应用于Optional
从而
有效地解开Optional
.
例如,如果user
是类型Optional<User>
,表达式user?.name
将
评估为null
如果user
是null
或空的 Optional
否则
评估为name
的user
有效user.get().getName()
或user.get().name
分别用于属性或字段访问。
调用 |
同样,如果names
是类型Optional<List<String>>
,表达式names?.?[#this.length > 5]
将评估为null
如果names
是null
或空的
Optional
否则将计算为包含长度
大于 5,有效names.get().stream().filter(s → s.length() > 5).toList()
.
相同的语义适用于前面提到的所有空安全运算符 章。
有关更多详细信息和示例,请参阅 javadoc 以获取以下运算符。
复合表达式中的空安全运算
如本节开头所述,当安全导航操作员
评估为null
对于复合表达式中的特定空安全作,
仍将评估化合物表达式的其余部分。这意味着
安全导航运算符必须应用于整个复合表达式,以便
避免任何不需要的NullPointerException
.
给定表达式#person?.address.city
如果#person
是null
安全导航
运算符 (?.
) 确保在尝试访问address
属性#person
.但是,由于#person?.address
评估为null
一个NullPointerException
在尝试访问city
属性null
.为了解决这个问题,您可以在整个化合物中应用空安全导航
表达式,如#person?.address?.city
.该表达式将安全地计算为null
如果#person
或#person?.address
评估为null
.
以下示例演示如何使用“空安全优先选择”运算符
(?.^
) 与空安全属性访问 (?.
) 在化合物中
表达。如果members
是null
,“空安全先选择”运算符的结果
(members?.^[nationality == 'Serbian']
) 的计算结果为null
,以及
安全导航操作员 (?.name
)确保整个化合物表达
评估为null
而不是抛出异常。
-
Java
-
Kotlin
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 | 在复合表达式中使用“空安全优先选择”和空安全属性访问运算符。 |
val parser = SpelExpressionParser()
val society = IEEE()
val context = StandardEvaluationContext(society)
val expression = "members?.^[nationality == 'Serbian']?.name" (1)
// evaluates to "Nikola Tesla"
String name = parser.parseExpression(expression)
.getValue(context, String::class.java)
society.members = null
// evaluates to null - does not throw a NullPointerException
name = parser.parseExpression(expression)
.getValue(context, String::class.java)
1 | 在复合表达式中使用“空安全优先选择”和空安全属性访问运算符。 |