セーフナビゲーション演算子

セーフナビゲーション演算子 (?) は、NullPointerException を回避するために使用され、Groovy (英語) 言語に由来します。通常、オブジェクトへの参照がある場合、オブジェクトのメソッドまたはプロパティにアクセスする前に、それが null ではないことを確認する必要がある場合があります。これを回避するために、セーフナビゲーションオペレーターは、例外をスローする代わりに、特定の null セーフ操作に対して null を返します。

複合式内の特定の null セーフ操作に対してセーフナビゲーション演算子が 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);
1null 以外の placeOfBirth プロパティでセーフナビゲーション演算子を使用する
2null 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)
1null 以外の placeOfBirth プロパティでセーフナビゲーション演算子を使用する
2null placeOfBirth プロパティでセーフナビゲーション演算子を使用する

セーフナビゲーション演算子は、オブジェクトのメソッド呼び出しにも適用されます。

例: #calculator 変数がコンテキスト内で構成されていない場合、式 #calculator?.max(4, 2) は null と評価されます。それ以外の場合は、max(int, int) メソッドが #calculator で呼び出されます。

安全なコレクションの選択と射影

Spring 式言語は、次の演算子によるコレクションの選択コレクションの射影のための安全なナビゲーションをサポートします。

  • null セーフ選択: ?.?

  • null セーフ選択を最初に行う: ?.^

  • null セーフ最後を選択: ?.$

  • null セーフ射影: ?.!

次の例は、コレクション選択にセーフナビゲーション演算子 (?.?) を使用する方法を示しています。

  • 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);
1null の可能性がある members リストに対して null セーフ選択演算子を使用する
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>
1null の可能性がある members リストに対して null セーフ選択演算子を使用する

次の例は、コレクション (?.^) に "null-safe select first" 演算子を使用する方法を示しています。

  • 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);
1null の可能性がある members リストに対して "null-safe select first" 演算子を使用する
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)
1null の可能性がある members リストに対して "null-safe select first" 演算子を使用する

次の例は、コレクション (?.$) に "null-safe select last" 演算子を使用する方法を示しています。

  • 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);
1null の可能性がある members リストに対して "null-safe select last" 演算子を使用する
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)
1null の可能性がある members リストに対して "null-safe select last" 演算子を使用する

次の例は、コレクション射影にセーフナビゲーション演算子 (?.!) を使用する方法を示しています。

  • 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);
1null 以外の members リストで null セーフな射影演算子を使用する
2null members リストで null セーフ射影演算子を使用する
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)
1null 以外の members リストで null セーフな射影演算子を使用する
2null members リストで null セーフ射影演算子を使用する

複合式での Null セーフ操作

このセクションの冒頭で記述されていたように、複合式内の特定の null セーフ操作に対してセーフナビゲーション演算子が null と評価される場合でも、複合式の残りの部分は評価されます。これは、不要な NullPointerException を回避するために、複合式全体にセーフナビゲーション演算子を適用する必要があることを意味します。

式 #person?.address.city を指定すると、#person が null の場合、セーフナビゲーションオペレーター (?.) は、#person の address プロパティにアクセスしようとしたときに例外がスローされないことを保証します。ただし、#person?.address は null として評価されるため、null の city プロパティにアクセスしようとすると NullPointerException がスローされます。これに対処するには、#person?.address?.city のように複合式全体に null セーフナビゲーションを適用します。#person または #person?.address が null と評価される場合、その式は安全に null と評価されます。

次の例は、複合式内でコレクションに対して "null-safe select first" 演算子 (?.^) を使用し、null-safe プロパティアクセス (?.) と組み合わせて使用する方法を示しています。members が null の場合、"null-safe select first" 演算子 (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 複合式内で "null-safe select first" および null-safe プロパティアクセス演算子を使用します。
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 複合式内で "null-safe select first" および null-safe プロパティアクセス演算子を使用します。