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";
}
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();
}
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
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.")
}
giveIfEvan :: Int -> Maybe Int
giveIfEvan n = if n `mod` 2 == 0
then Just n
else Nothing
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
JDK 1.7 까지...
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);
//Optional<Integer> a, Optional<Integer> b
// 값이 없는 경우 인수로 받은 값을 반환
Integer value1 = a.or(new Integer(0));
// 값이 없는경우 throws an IllegalStateException.
Integer value2 = b.get();
JDK 1.8 +
Apple
Optional<Apple>
Optional<Apple>
Empty
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; };
}
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);
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");
예상하지 못한 NPE 발생을 방지 할수 있다.
값이 반드시 있어야 하는 것과 아닌 것을 구분할 수 있다.
값이 없는 상황을 일관되게 처리하도록 강제 할 수 있다.
불필요한 코드를 줄일 수 있다. 가독성을 높힌다.