Loading...
Spring Framework Reference Documentation 7.0.2의 Safe Navigation Operator의 한국어 번역본입니다.
아래의 경우에 피드백에서 신고해주신다면 반영하겠습니다.
감사합니다 :)
Safe navigation operator (?.)는 NullPointerException을 피하기 위해 사용되며
Groovy
language에서 왔습니다. 일반적으로 어떤 객체에 대한 reference가 있을 때, 그 객체의 메서드나 property에 접근하기 전에
그것이 null이 아닌지 확인해야 할 수도 있습니다.
이를 피하기 위해, safe navigation operator는 exception을 던지는 대신
특정 null-safe operation에 대해 null을 반환합니다.
Safe navigation operator가 compound expression 내의 특정 null-safe operation에 대해
null로 평가될 때, compound expression의 나머지 부분은 여전히 평가됩니다. 자세한 내용은 Null-safe Operations in Compound Expressions를 참조하십시오.
다음 예제는 property access (?.)에 safe navigation operator를 사용하는 방법을 보여줍니다.
1ExpressionParser parser = new SpelExpressionParser(); 2EvaluationContext context = SimpleEvaluationContext.forReadOnlyDataBinding().build(); 3 4Inventor tesla = new Inventor("Nikola Tesla", "Serbian"); 5tesla.setPlaceOfBirth(new PlaceOfBirth("Smiljan")); 6 7// evaluates to "Smiljan" 8String city = parser.parseExpression("placeOfBirth?.city") // (1) 9 .getValue(context, tesla, String.class); 10 11tesla.setPlaceOfBirth(null); 12 13// evaluates to null - does not throw NullPointerException 14city = parser.parseExpression("placeOfBirth?.city") // (2) 15 .getValue(context, tesla, String.class);
| 1 | null이 아닌 placeOfBirth property에 safe navigation operator 사용 |
| 2 | null인 placeOfBirth property에 safe navigation operator 사용 |
1val parser = SpelExpressionParser() 2val context = SimpleEvaluationContext.forReadOnlyDataBinding().build() 3 4val tesla = Inventor("Nikola Tesla", "Serbian") 5tesla.setPlaceOfBirth(PlaceOfBirth("Smiljan")) 6 7// evaluates to "Smiljan" 8var city = parser.parseExpression("placeOfBirth?.city") // (1) 9 .getValue(context, tesla, String::class.java) 10 11tesla.setPlaceOfBirth(null) 12 13// evaluates to null - does not throw NullPointerException 14city = parser.parseExpression("placeOfBirth?.city") // (2) 15 .getValue(context, tesla, String::class.java)
| 1 | null이 아닌 placeOfBirth property에 safe navigation operator 사용 |
| 2 | null인 placeOfBirth property에 safe navigation operator 사용 |
Safe navigation operator는 객체에 대한 메서드 invocation에도 적용됩니다. 예를 들어, expression
#calculator?.max(4, 2)는#calculatorvariable이 context에 설정되지 않은 경우null로 평가됩니다. 그렇지 않으면max(int, int)메서드가#calculator에 대해 호출됩니다.
Spring Framework 6.2부터 Spring Expression Language는 다음과 같은 구조에 대한 indexing에 safe navigation을 지원합니다.
다음 예제는 list (?.[])에 대한 indexing에 safe navigation operator를 사용하는 방법을 보여줍니다.
1ExpressionParser parser = new SpelExpressionParser(); 2IEEE society = new IEEE(); 3EvaluationContext context = new StandardEvaluationContext(society); 4 5// evaluates to Inventor("Nikola Tesla") 6Inventor inventor = parser.parseExpression("members?.[0]") // (1) 7 .getValue(context, Inventor.class); 8 9society.members = null; 10 11// evaluates to null - does not throw an exception 12inventor = parser.parseExpression("members?.[0]") // (2) 13 .getValue(context, Inventor.class);
| 1 | null이 아닌 members list에 null-safe index operator 사용 |
| 2 | null인 members list에 null-safe index operator 사용 |
1val parser = SpelExpressionParser() 2val society = IEEE() 3val context = StandardEvaluationContext(society) 4 5// evaluates to Inventor("Nikola Tesla") 6var inventor = parser.parseExpression("members?.[0]") // (1) 7 .getValue(context, Inventor::class.java) 8 9society.members = null 10 11// evaluates to null - does not throw an exception 12inventor = parser.parseExpression("members?.[0]") // (2) 13 .getValue(context, Inventor::class.java)
| 1 | null이 아닌 members list에 null-safe index operator 사용 |
| 2 | null인 members list에 null-safe index operator 사용 |
Spring Expression Language는 다음 operator를 통해 collection selection과 collection projection에 대한 safe navigation을 지원합니다.
?.??.^?.$?.!다음 예제는 collection selection (?.?)에 safe navigation operator를 사용하는 방법을 보여줍니다.
1ExpressionParser parser = new SpelExpressionParser(); 2IEEE society = new IEEE(); 3StandardEvaluationContext context = new StandardEvaluationContext(society); 4String expression = "members?.?[nationality == 'Serbian']"; // (1) 5 6// evaluates to [Inventor("Nikola Tesla")] 7List<Inventor> list = (List<Inventor>) parser.parseExpression(expression) 8 .getValue(context); 9 10society.members = null; 11 12// evaluates to null - does not throw a NullPointerException 13list = (List<Inventor>) parser.parseExpression(expression) 14 .getValue(context);
| 1 | 잠재적으로 null인 members list에 null-safe selection operator 사용 |
1val parser = SpelExpressionParser() 2val society = IEEE() 3val context = StandardEvaluationContext(society) 4val expression = "members?.?[nationality == 'Serbian']" // (1) 5 6// evaluates to [Inventor("Nikola Tesla")] 7var list = parser.parseExpression(expression) 8 .getValue(context) as List<Inventor> 9 10society.members = null 11 12// evaluates to null - does not throw a NullPointerException 13list = parser.parseExpression(expression) 14 .getValue(context) as List<Inventor>
| 1 | 잠재적으로 null인 members list에 null-safe selection operator 사용 |
다음 예제는 collection (?.^)에 "null-safe select first" operator를 사용하는 방법을 보여줍니다.
1ExpressionParser parser = new SpelExpressionParser(); 2IEEE society = new IEEE(); 3StandardEvaluationContext context = new StandardEvaluationContext(society); 4String expression = 5 "members?.^[nationality == 'Serbian' || nationality == 'Idvor']"; // (1) 6 7// evaluates to Inventor("Nikola Tesla") 8Inventor inventor = parser.parseExpression(expression) 9 .getValue(context, Inventor.class); 10 11society.members = null; 12 13// evaluates to null - does not throw a NullPointerException 14inventor = parser.parseExpression(expression) 15 .getValue(context, Inventor.class);
| 1 | 잠재적으로 null인 members list에 "null-safe select first" operator 사용 |
1val parser = SpelExpressionParser() 2val society = IEEE() 3val context = StandardEvaluationContext(society) 4val expression = 5 "members?.^[nationality == 'Serbian' || nationality == 'Idvor']" // (1) 6 7// evaluates to Inventor("Nikola Tesla") 8var inventor = parser.parseExpression(expression) 9 .getValue(context, Inventor::class.java) 10 11society.members = null 12 13// evaluates to null - does not throw a NullPointerException 14inventor = parser.parseExpression(expression) 15 .getValue(context, Inventor::class.java)
| 1 | 잠재적으로 null인 members list에 "null-safe select first" operator 사용 |
다음 예제는 collection (?.$)에 "null-safe select last" operator를 사용하는 방법을 보여줍니다.
1ExpressionParser parser = new SpelExpressionParser(); 2IEEE society = new IEEE(); 3StandardEvaluationContext context = new StandardEvaluationContext(society); 4String expression = 5 "members?.$[nationality == 'Serbian' || nationality == 'Idvor']"; // (1) 6 7// evaluates to Inventor("Pupin") 8Inventor inventor = parser.parseExpression(expression) 9 .getValue(context, Inventor.class); 10 11society.members = null; 12 13// evaluates to null - does not throw a NullPointerException 14inventor = parser.parseExpression(expression) 15 .getValue(context, Inventor.class);
| 1 | 잠재적으로 null인 members list에 "null-safe select last" operator 사용 |
1val parser = SpelExpressionParser() 2val society = IEEE() 3val context = StandardEvaluationContext(society) 4val expression = 5 "members?.$[nationality == 'Serbian' || nationality == 'Idvor']" // (1) 6 7// evaluates to Inventor("Pupin") 8var inventor = parser.parseExpression(expression) 9 .getValue(context, Inventor::class.java) 10 11society.members = null 12 13// evaluates to null - does not throw a NullPointerException 14inventor = parser.parseExpression(expression) 15 .getValue(context, Inventor::class.java)
| 1 | 잠재적으로 null인 members list에 "null-safe select last" operator 사용 |
다음 예제는 collection projection (?.!)에 safe navigation operator를 사용하는 방법을 보여줍니다.
1ExpressionParser parser = new SpelExpressionParser(); 2IEEE society = new IEEE(); 3StandardEvaluationContext context = new StandardEvaluationContext(society); 4 5// evaluates to ["Smiljan", "Idvor"] 6List placesOfBirth = parser.parseExpression("members?.![placeOfBirth.city]") // (1) 7 .getValue(context, List.class); 8 9society.members = null; 10 11// evaluates to null - does not throw a NullPointerException 12placesOfBirth = parser.parseExpression("members?.![placeOfBirth.city]") // (2) 13 .getValue(context, List.class);
| 1 | null이 아닌 members list에 null-safe projection operator 사용 |
| 2 | null인 members list에 null-safe projection operator 사용 |
1val parser = SpelExpressionParser() 2val society = IEEE() 3val context = StandardEvaluationContext(society) 4 5// evaluates to ["Smiljan", "Idvor"] 6var placesOfBirth = parser.parseExpression("members?.![placeOfBirth.city]") // (1) 7 .getValue(context, List::class.java) 8 9society.members = null 10 11// evaluates to null - does not throw a NullPointerException 12placesOfBirth = parser.parseExpression("members?.![placeOfBirth.city]") // (2) 13 .getValue(context, List::class.java)
| 1 | null이 아닌 members list에 null-safe projection operator 사용 |
| 2 | null인 members list에 null-safe projection operator 사용 |
OptionalSpring Framework 7.0부터 null-safe operation은 투명한 unwrapping semantics와 함께
java.util.Optional instance에 대해 지원됩니다.
구체적으로, null-safe operator가 emptyOptional에 적용되면,
Optional이 null인 것처럼 취급되고, 이후의 operation은 null로 평가됩니다.
그러나 null-safe operator가 non-empty Optional에 적용되면,
이후의 operation은 Optional에 포함된 객체에 적용되어,
결과적으로 Optional을 효과적으로 unwrapping합니다.
예를 들어, user가 Optional<User> type이라면, expression user?.name은
user가 null이거나 emptyOptional인 경우 null로 평가되고,
그렇지 않으면 user의 name으로 평가됩니다.
이는 property 또는 field access에 대해
각각 user.get().getName() 또는 user.get().name과 같습니다.
OptionalAPI에 정의된 메서드의 invocation은 emptyOptional에 대해서도 여전히 지원됩니다. 예를 들어,name이Optional<String>type이라면, expressionname?.orElse('Unknown')은name이 emptyOptional인 경우"Unknown"으로 평가되고, 그렇지 않으면name이 non-emptyOptional인 경우Optional에 포함된String으로 평가되며, 이는 사실상name.get()과 같습니다.
마찬가지로, names가 Optional<List<String>> type이라면,
expression names?.?[#this.length > 5]는 names가 null이거나 emptyOptional인 경우 null로 평가되고,
그렇지 않으면 길이가 5보다 큰 name을 포함하는 sequence로 평가되며,
이는 사실상 names.get().stream().filter(s → s.length() > 5).toList()와 같습니다.
앞에서 이 장에서 언급된 모든 null-safe operator에 동일한 semantics가 적용됩니다.
자세한 내용과 예제는 다음 operator에 대한 javadoc을 참조하십시오.
이 section의 시작 부분에서 언급했듯이, safe navigation operator가
compound expression 내의 특정 null-safe operation에 대해 null로 평가될 때,
compound expression의 나머지 부분은 여전히 평가됩니다.
이는
원치 않는 NullPointerException을 피하려면 safe navigation operator가
compound expression 전체에 걸쳐 적용되어야 함을 의미합니다.
expression #person?.address.city를 보면, #person이 null인 경우
safe navigation operator (?.)는 #person의 address property에 접근하려고 할 때
어떤 exception도 던져지지 않도록 보장합니다. 그러나 #person?.address가 null로 평가되므로,
null의 city property에 접근하려고 할 때 NullPointerException이 발생합니다.
이를 해결하기 위해, #person?.address?.city와 같이 compound expression 전체에
null-safe navigation을 적용할 수 있습니다. 그 expression은 #person 또는
#person?.address가 null로 평가되는 경우 안전하게 null로 평가됩니다.
다음 예제는 collection에 대한 "null-safe select first" operator (?.^)를
compound expression 내에서 null-safe property access (?.)와 결합하여 사용하는 방법을 보여줍니다.
members가 null인 경우, "null-safe select first" operator의 결과
(members?.^[nationality == 'Serbian'])는 null로 평가되며,
safe navigation operator (?.name)를 추가로 사용함으로써
exception을 던지는 대신 전체 compound expression이 null로 평가되도록 보장합니다.
1ExpressionParser parser = new SpelExpressionParser(); 2IEEE society = new IEEE(); 3StandardEvaluationContext context = new StandardEvaluationContext(society); 4String expression = "members?.^[nationality == 'Serbian']?.name"; // (1) 5 6// evaluates to "Nikola Tesla" 7String name = parser.parseExpression(expression) 8 .getValue(context, String.class); 9 10society.members = null; 11 12// evaluates to null - does not throw a NullPointerException 13name = parser.parseExpression(expression) 14 .getValue(context, String.class);
| 1 | compound expression 내에서 "null-safe select first"와 null-safe property access operator 사용. |
1val parser = SpelExpressionParser() 2val society = IEEE() 3val context = StandardEvaluationContext(society) 4val expression = "members?.^[nationality == 'Serbian']?.name" // (1) 5 6// evaluates to "Nikola Tesla" 7val name = parser.parseExpression(expression) 8 .getValue(context, String::class.java) 9 10society.members = null 11 12// evaluates to null - does not throw a NullPointerException 13val name2 = parser.parseExpression(expression) 14 .getValue(context, String::class.java)
| 1 | compound expression 내에서 "null-safe select first"와 null-safe property access operator 사용. |
The Elvis Operator
Collection Selection