null reference

null reference

누가 만들었나?

Null References:

The Billion Dollar Mistake

일반적인 상황들

public class Person {
	private Home home;
	public Home getHome() { return home; };
}

public class Home {
	private Furniture furniture ;
	public Furniture getFurniture() { return furniture;  }; 
}

public class Furniture {
	private String name;
	public String getName() { return name; };
}

평범한 클래스

public String getFurnitureName(Person person) {
	return person.getHome().getFurniture().getName();
}

믿음.. 신뢰.. 신용..

public String getFurnitureName(Person person) {
	if (person != null) {
		Home home = person.getHome();
		if (home != null) {
			Furniture furniture = home.getFurniture();
			if (furniture != null) {
				return furniture.getName();
			}
		}
	}
	
	return "NoName";
}

깊은 의심(deep doubt)

public String getFurnitureName(Person person) {
	if (person == null) {
		return "NoName";
	}
	
	Home home = person.getHome();
	if (home == null) {
		return "NoName";
	}

	Furniture furniture = home.getFurniture();
	if (furniture == null) {
		return "NoName";
	}
	
	return furniture.getName();
}

빠른 return! 

null의 문제점

NullPointerException (NPE)

if(domain != null) {
  if(domain.getKingdom() != null) {
    if(domain.getKingdom().getPhylum() != null) {
      if(domain.getKingdom().getPhylum().getClass() != null) {
        if(domain.getKingdom().getPhylum().getClass().getOrder() != null) {
          if(domain.getKingdom().getPhylum().getClass().getOrder().getFamily() != null) {
            if(domain.getKingdom().getPhylum().getClass().getOrder().getFamily().getGenus() != null) {
                // safe?
        }
      }
    }
  }
}

가독성

    Map<String, Object> myMap = new HashMap<>();
    myMap.put("myKey", null);

    (myMap.get("myKey") == myMap.get("mikey")) ????

일반적인 의미가 없음

    String string = null;
    Integer integer = null;
    Long loong = null;
    Map<String, Object> map = null;
    
    ...

일반적인 의미가 없음

    String str = null;
    str = str + "hello"; // NPE???
    System.out.println(str);

결과를 예측하기 어려움

String str = null;
str = new StringBuilder(String.valueOf(str)).append("hello").toString();
System.out.println(str); // "nullhello"



public static String valueOf(Object obj) {
    return (obj == null) ? "null" : obj.toString();
}

결과를 예측하기 어려움

공통적인 관심사

java, c, c++, scala, swift ...

def person = Person.find { it.id == 123 }
def name = person?.name                      
assert name == null

Groovy
Safe navigation operator

class Person {
    var residence: Residence? // nil 로 초기화
}
 
class Residence {
    var numberOfRooms = 1 // nil이 될 수 없음. 초기화 필요
}



let john = Person()
if let roomCount = john.residence?.numberOfRooms { // Optional Chaining
    print("John's residence has \(roomCount) room(s).")
} else {
    print("Unable to retrieve the number of rooms.")
}

Swift 

Optional Type

giveIfEvan :: Int -> Maybe Int
giveIfEvan n = if n `mod` 2 == 0
                then Just n 
                else Nothing

Haskell

Maybe

      val a:Option[Int] = Some(5)
      val b:Option[Int] = None 
      
      println("a.getOrElse(0): " + a.getOrElse(0) ) // 5
      println("b.getOrElse(10): " + b.getOrElse(10) ) // 10

Scala

Option[T]

그렇다면 JAVA는?

JDK 1.7 까지...

GUAVA -
Google Core Libraries for Java

Requires JDK 1.6 or higher (as of 12.0).

      Integer value1 =  null;
      Integer value2 =  new Integer(10);
      
      // null을 허용한다.
      Optional<Integer> a = Optional.fromNullable(value1);
      
      // null을 허용하지 않는다.
      Optional<Integer> b = Optional.of(value2);	

Guava

Optional<T>

      //Optional<Integer> a, Optional<Integer> b

      // 값이 없는 경우 인수로 받은 값을 반환
      Integer value1 = a.or(new Integer(0));	

      // 값이 없는경우 throws an IllegalStateException.
      Integer value2 = b.get();

Guava

Optional<T>

Guava

Optional<T>

java.util.Optional<T>

JDK 1.8 +

Optional<T>

Apple

Optional<Apple>

Optional<Apple>

Empty

Optional<T>

public class Person {
  private Optional<Home> home;
  public Optional<Home> getHome() { return home; };
}

public class Home {
  private Optional<Furniture> furniture ;
  public Optional<Furniture> getFurniture() { return furniture;  }; 
}

public class Furniture {
  private String name;
  public String getName() { return name; };
}

Optional<T>

    Person person = new Person();
    if (person != null) {
      Home home = person.getHome();
    }
    

    // java 8
    Optional<Person> person = Optional.of(new Person());
    Option<Home> home = person.map(Person::getHome);

Optional<T>

    if (person != null) {
      Home home = person.getHome();
      if (home != null) {
          Furniture furniture = home.getFurniture();
          if (furniture != null) {
              return furniture.getName();
          }
      }
    }
    
    return "NoName";
    

    // java 8
    person.flatMap(Person::getHome)
          .flatMap(Home::getFurniture)
          .map(Furniture::getName)
          .orElse("NoName");

Optional<T>

Optional<T>의 장점

  • 예상하지 못한 NPE 발생을 방지 할수 있다.

  • 값이 반드시 있어야 하는 것과 아닌 것을 구분할 수 있다.

  • 값이 없는 상황을 일관되게 처리하도록 강제 할 수 있다.

  • 불필요한 코드를 줄일 수 있다. 가독성을 높힌다.

null reference

By serivires

null reference

  • 663