3. null?
• ‘값이 없음’을 나타내는 영단어, 값이 없다는 것은 그 값이 0
조차 아니라는 뜻이다. 독일어 에선 숫자 0을 뜻한다.
• ASCII코드는 0, 유니 코드는 U+0000 이 널 문자다.
• C 프로그래밍에서는 ‘존재하지 않는 메모리 주소’를 NULL
로 나타낸다.
• 존재 하지 않는 값 을 나타낸다.
4. null 이 왜?
• null 을 고안한 Tony Hore는 Billion Dollar Mistake 라고 후
회 함
10. public Person findPersonByName(String name) {
long id = db.findPersonIdByName(name);
if (id == -1) {
return null;
} else {
return new Person(id, name, null);
}
}
null 이 왜?
11. null 이 왜?
Person person = findPersonByName("lazysoul");
/* person is nonNull */
String name = person.name;
12. null 이 왜?
Person person = findPersonByName("lazysoul");
/* person is null */
String name = person.name;
13. null 이 왜?
Person person = findPersonByName("lazysoul");
/* person is null */
String name = person.name; // NullPointerException
14. null 이 왜?
Person person = findPersonByName("lazysoul");
/* person is null */
String name = person.name; // NullPointerException
• 런타임에 의도치 않은 NPE 발생시킨다.
18. 명령형 프로그래밍 회피
Person person = findPersonByName("lazysoul");
/* person is null */
String name = person.name; // NullPointerException
19. 명령형 프로그래밍 회피
Person person = findPersonByName(“lazysoul");
/* person is null */
String name = "default";
if (person != null) {
name = person.name;
}
20. 명령형 프로그래밍 회피
Person person = findPersonByName(“lazysoul");
/* person is null */
String name = "default";
if (person != null) {
name = person.name;
} Dog 의 name 을 가져오고 싶다면?
21. 명령형 프로그래밍 회피
Person person = findPersonByName("lazysoul");
/* person is null */
String name = “default";
if (person != null) {
Dog dog = person.dog;
if (dog != null) {
name = dog.name;
}
}
22. Person person = findPersonByName("lazysoul");
/* person is null */
String name = "default";
if (person != null) {
Dog dog = person.dog;
if (dog != null) {
name = dog.name;
}
}
명령형 프로그래밍 회피
Something name을 가져오고 싶다면?
23. Person person = findPersonByName("lazysoul");
/* person is null */
String name = "default";
if (person != null) {
Dog dog = person.dog;
if (dog != null) {
Something something = dog.something;
if(something != null){
name = something.name;
}
}
}
명령형 프로그래밍 회피
40. abstract class AbstractPerson {
long id;
String name;
AbstractDog dog;
abstract boolean isNull();
}
class Person extends AbstractPerson {
Person(long id, String name, AbstractDog dog) {
this.id = id;
this.name = name;
this.dog = dog;
}
@Override
boolean isNull() {
return false;
}
}
class NullPerson extends AbstractPerson {
NullPerson() {
this.id = -1;
this.name = "person is null";
this.dog = new NullDog();
}
@Override
boolean isNull() {
return true;
}
추상화를 통한 회피
41. abstract class AbstractPerson {
long id;
String name;
AbstractDog dog;
abstract boolean isNull();
}
class Person extends AbstractPerson {
Person(long id, String name, AbstractDog dog) {
this.id = id;
this.name = name;
this.dog = dog;
}
@Override
boolean isNull() {
return false;
}
}
class NullPerson extends AbstractPerson {
NullPerson() {
this.id = -1;
this.name = "person is null";
this.dog = new NullDog();
}
@Override
boolean isNull() {
return true;
}
추상화를 통한 회피
42. abstract class AbstractPerson {
long id;
String name;
AbstractDog dog;
abstract boolean isNull();
}
class Person extends AbstractPerson {
Person(long id, String name, AbstractDog dog) {
this.id = id;
this.name = name;
this.dog = dog;
}
@Override
boolean isNull() {
return false;
}
}
class NullPerson extends AbstractPerson {
NullPerson() {
this.id = -1;
this.name = "person is null";
this.dog = new NullDog();
}
@Override
boolean isNull() {
return true;
}
추상화를 통한 회피
43. abstract class AbstractPerson {
long id;
String name;
AbstractDog dog;
abstract boolean isNull();
}
class Person extends AbstractPerson {
Person(long id, String name, AbstractDog dog) {
this.id = id;
this.name = name;
this.dog = dog;
}
@Override
boolean isNull() {
return false;
}
}
class NullPerson extends AbstractPerson {
NullPerson() {
this.id = -1;
this.name = "person is null";
this.dog = new NullDog();
}
@Override
boolean isNull() {
return true;
}
추상화를 통한 회피
44. public Person findPersonByName(String name) {
long id = db.findPersonIdByName(name);
if (id == -1) {
return null;
} else {
return new Person(id, name, null);
}
}
추상화를 통한 회피
45. public AbstractPerson findPersonByName(String name) {
long id = db.findPersonIdByName(name);
if (id == -1) {
return new NullPerson();
} else {
return new Person(id, name, null);
}
}
추상화를 통한 회피
46. 추상화를 통한 회피
Person person = findPersonByName("lazysoul");
/* person is null */
String name = person.name; // NullPointerException
47. AbstractPerson person = findPersonByName(“lazysoul");
/* person is null */
String name = person.name; // Nothing
추상화를 통한 회피
48. Dog 의 name 을 가져오고 싶다면?
추상화를 통한 회피
AbstractPerson person = findPersonByName(“lazysoul");
/* person is null */
String name = person.name; // Nothing
49. AbstractPerson person = findPersonByName("lazysoul");
/* person is null */
String name = "default";
AbstractDog dog = person.dog;
name = dog.name;
추상화를 통한 회피
50. Something 의 name 을 가져오고 싶다면?
추상화를 통한 회피
AbstractPerson person = findPersonByName("lazysoul");
/* person is null */
String name = "default";
AbstractDog dog = person.dog;
name = dog.name;
51. 추상화를 통한 회피
AbstractPerson person = findPersonByName("lazysoul");
/* person is null */
String name = "default";
AbstractDog dog = person.dog;
AbstractSomething something = dog.something;
name = something.name;
52. • 런타임에 NPE가 발생하지 않는다.
추상화를 통한 회피
AbstractPerson person = findPersonByName("lazysoul");
/* person is null */
String name = "default";
AbstractDog dog = person.dog;
AbstractSomething something = dog.something;
name = something.name;
53. • 런타임에 NPE가 발생하지 않는다.
• 가독성이 좋다.
추상화를 통한 회피
AbstractPerson person = findPersonByName("lazysoul");
/* person is null */
String name = "default";
AbstractDog dog = person.dog;
AbstractSomething something = dog.something;
name = something.name;
54. • 런타임에 NPE가 발생하지 않는다.
• 가독성이 좋다.
• 의미 없는 값을 출력 한다. (crash 가 좋을 수도 있다.)
추상화를 통한 회피
AbstractPerson person = findPersonByName("lazysoul");
/* person is null */
String name = "default";
AbstractDog dog = person.dog;
AbstractSomething something = dog.something;
name = something.name;
55. nonNull인 경우에만 특정 비지니스 로직을 수행하려면?
추상화를 통한 회피
AbstractPerson person = findPersonByName("lazysoul");
/* person is null */
String name = "default";
AbstractDog dog = person.dog;
AbstractSomething something = dog.something;
name = something.name;
56. 추상화를 통한 회피
AbstractPerson person = findPersonByName("lazysoul");
String name = "default";
if (!person.isNull()) {
AbstractDog dog = person.dog;
if (!dog.isNull()) {
AbstractSomething something = dog.something;
if (!something.isNull()) {
name = something.name;
}
}
}
57. AbstractPerson person = findPersonByName("lazysoul");
String name = "default";
if (!person.isNull()) {
AbstractDog dog = person.dog;
if (!dog.isNull()) {
AbstractSomething something = dog.something;
if (!something.isNull()) {
name = something.name;
}
}
}
추상화를 통한 회피
58. AbstractPerson person = findPersonByName("lazysoul");
String name = "default";
if (!person.isNull()) {
AbstractDog dog = person.dog;
if (!dog.isNull()) {
AbstractSomething something = dog.something;
if (!something.isNull()) {
name = something.name;
}
}
}
• nonNull을 의미하는 값에 접근을 하려면 어차피 null check
를 해야 한다.
추상화를 통한 회피
61. • 런타임에 NPE가 발생하지 않는다.
• 가독성이 좋다.
• 의미 없는 값을 출력 한다. (crash 가 좋을 수도 있다.)
추상화를 통한 회피
62. • 런타임에 NPE가 발생하지 않는다.
• 가독성이 좋다.
• 의미 없는 값을 출력 한다. (crash 가 좋을 수도 있다.)
• nonNull을 의미하는 값에 접근을 하려면 어차피 null check
를 해야 한다.
추상화를 통한 회피
63. • 런타임에 NPE가 발생하지 않는다.
• 가독성이 좋다.
• 의미 없는 값을 출력 한다. (crash 가 좋을 수도 있다.)
• nonNull을 의미하는 값에 접근을 하려면 어차피 null check
를 해야 한다.
• Abstract class, 실제 class, nullableClass 를 만들어줘야 하
기 때문에 보일러 플레이트들이 많다.
추상화를 통한 회피
65. 언어적 회피 - Kotlin
data class Person(val id: Long, val name: String, val dog: Dog?)
data class Dog(val name: String, val something: Something?)
data class Something(val name: String)
66. 언어적 회피 - Kotlin
data class Person(val id: Long, val name: String, val dog: Dog?)
data class Dog(val name: String, val something: Something?)
data class Something(val name: String)
68. 언어적 회피 - Kotlin
val nullable: String? = null
val nonNull: String = null
//Null can not be a value of a non-null type String
69. 언어적 회피 - Kotlin
val nullable: String? = null
val result: String = nullable ?: "default"
70. 언어적 회피 - Kotlin
val nullable: String? = null
val result: String = nullable ?: "default"
71. 언어적 회피 - Kotlin
Person person = findPersonByName("lazysoul");
/* person is null */
String name = person.name; // NullPointerException
72. 언어적 회피 - Kotlin
/* person is null */
val name: String? = findPersonByName("lazysoul")
?.name ?: "default"
73. 언어적 회피 - Kotlin
Dog 의 name 을 가져오고 싶다면?
/* person is null */
val name: String? = findPersonByName("lazysoul")
?.name ?: "default"
74. 언어적 회피 - Kotlin
/* person is null */
val name: String? = findPersonByName("lazysoul")
?.dog
?.name ?: "default"
75. 언어적 회피 - Kotlin
Something 의 name 을 가져오고 싶다면?
/* person is null */
val name: String? = findPersonByName("lazysoul")
?.dog
?.name ?: "default"
76. 언어적 회피 - Kotlin
/* person is null */
val name: String? = findPersonByName("lazysoul")
?.dog
?.something
?.name ?: "default"
77. 언어적 회피 - Kotlin
Person person = findPersonByName("lazysoul");
/* person is null */
String name = “default";
if (person != null) {
Dog dog = person.dog;
if (dog != null) {
Something something = dog.something;
if(something != null){
name = something.name;
}
}
}
/* person is null */
val name: String? = findPersonByName("lazysoul")
?.dog
?.something
?.name ?: "default"
91. FP 적 회피
lazysoul
Optional
String value = “lazysoul”
String value = null
Optional.ofNullable(value)
Optional.ofNullable(value)
empty
Optional
92. FP 적 회피
class Something {
String name;
Something(String name) {
this.name = name;
}
}
93. FP 적 회피
class Dog {
String name;
private Something something;
Dog(String name, Something something) {
this.name = name;
this.something = something;
}
public Optional<Something> getSomething() {
return Optional.ofNullable(something);
}
}
94. FP 적 회피
class Dog {
String name;
private Something something;
Dog(String name, Something something) {
this.name = name;
this.something = something;
}
public Optional<Something> getSomething() {
return Optional.ofNullable(something);
}
}
95. FP 적 회피
class Person {
long id;
String name;
private Dog dog;
Person(long id, String name, Dog dog) {
this.id = id;
this.name = name;
this.dog = dog;
}
public Optional<Dog> getDog() {
return Optional.ofNullable(dog);
}
}
96. FP 적 회피
class Person {
long id;
String name;
private Dog dog;
Person(long id, String name, Dog dog) {
this.id = id;
this.name = name;
this.dog = dog;
}
public Optional<Dog> getDog() {
return Optional.ofNullable(dog);
}
}
97. FP 적 회피
public Optional<Person> findPersonByName(String name) {
long id = db.findPersonIdByName(name);
if (id == -1) {
return Optional.empty();
} else {
return Optional.of(new Person(id, name, null));
}
}
98. FP 적 회피
Optional<Person> person = findPersonByName("lazysoul");
/* person is empty */
String name = “default";
if (person.isPresent()) {
name = person.get().name;
}
99. FP 적 회피
Optional<Person> person = findPersonByName("lazysoul");
/* person is empty */
String name = “default";
if (person.isPresent()) {
name = person.get().name;
}
100. FP 적 회피
Dog 의 name 을 가져오고 싶다면?
Optional<Person> person = findPersonByName("lazysoul");
/* person is empty */
String name = “default";
if (person.isPresent()) {
name = person.get().name;
}
101. FP 적 회피
Optional<Person> person = findPersonByName("lazysoul");
/* person is empty */
String name = "default";
if (person.isPresent()) {
Optional<Dog> dog = person.get().getDog();
if (dog.isPresent()) {
name = dog.get().name;
}
}
102. FP 적 회피
Something 의 name 을 가져오고 싶다면?
Optional<Person> person = findPersonByName("lazysoul");
/* person is empty */
String name = "default";
if (person.isPresent()) {
Optional<Dog> dog = person.get().getDog();
if (dog.isPresent()) {
name = dog.get().name;
}
}
103. FP 적 회피
Optional<Person> person = findPersonByName("lazysoul");
/* person is empty */
String name = “default";
if (person.isPresent()) {
Optional<Dog> dog = person.get().getDog();
if (dog.isPresent()) {
Optional<Something> something = dog.get().getSomething();
if(something.isPresent()){
name = something.get().name;
}
}
}
104. FP 적 회피
뭐가 이렇게 복잡해??
Optional<Person> person = findPersonByName("lazysoul");
/* person is empty */
String name = “default";
if (person.isPresent()) {
Optional<Dog> dog = person.get().getDog();
if (dog.isPresent()) {
Optional<Something> something = dog.get().getSomething();
if(something.isPresent()){
name = something.get().name;
}
}
}
108. FP 적 회피
String name = findPersonByName("lazysoul")
.flatMap(Person::getDog)
.flatMap(Dog::getSomething)
.map((something) -> something.name)
.orElse("default");
Person person = findPersonByName("lazysoul");
/* person is null */
String name = "default";
if (person != null) {
Dog dog = person.dog;
if (dog != null) {
Something something = dog.something;
if(something != null) {
name = something.name;
}
}
}