安全導航運算子
安全導航運算子 (?.
) 用於避免 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 | 在非空值 placeOfBirth 屬性上使用安全導航運算子 |
2 | 在空值 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 | 在非空值 placeOfBirth 屬性上使用安全導航運算子 |
2 | 在空值 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 | 在非空值 members 列表上使用空值安全索引運算子 |
2 | 在空值 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 | 在非空值 members 列表上使用空值安全索引運算子 |
2 | 在空值 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 | 在可能為空值的 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 | 在可能為空值的 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 | 在可能為空值的 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 | 在可能為空值的 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 | 在可能為空值的 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 | 在可能為空值的 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 | 在空值 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 | 在空值 members 列表上使用空值安全投影運算子 |
複合運算式中的空值安全操作
如本節開頭所述,當安全導航運算子在複合運算式中針對特定的空值安全操作評估為 null
時,複合運算式的其餘部分仍將被評估。 這表示必須在整個複合運算式中應用安全導航運算子,才能避免任何不必要的 NullPointerException
。
給定運算式 #person?.address.city
,如果 #person
為 null
,則安全導航運算子 (?.
) 可確保在嘗試存取 #person
的 address
屬性時不會拋出例外。 但是,由於 #person?.address
評估為 null
,因此在嘗試存取 null
的 city
屬性時會拋出 NullPointerException
。 為了解決這個問題,您可以像在 #person?.address?.city
中一樣,在整個複合運算式中應用空值安全導航。 如果 #person
或 #person?.address
評估為 null
,則該運算式將安全地評估為 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 | 在複合運算式中使用「空值安全選擇第一個」和空值安全屬性存取運算子。 |