본문으로 건너뛰기

Optional 기본

{{< youtube vX3yY_36Sk4 >}}

영상 요약


서적 지식

int, long, double 등의 원시형 데이터를 다룰 때에는
OptionalInt, OptionalLong, OptionalDouble와 같은 전용클래스를 이용하면 랩퍼 형으로 형변환을 하지 않아도 되므로 효율적인 옵셔널을 사용하기에 좋다.
원시형 데이터 에서의 Null을 다룰 때에는 꼭 써보자

기본구문

옵셔널 오브젝트의 생성법
public class Exercise1 {

public static void main(String[] args) {

// of의 경우에는 직접 null을 넣으면 예외로 스로우 된다.
Optional<String> exist = Optional.of("abc");
System.out.println(exist);


// 값을 갖고 있지 않은 비어있는 옵셔널 오브젝트 생
Optional<String> empty = Optional.empty();
System.out.println(empty);

// 값이 null이외일경우 에는 값을 갖고 있는 옵셔널,
// 값이 null일 때에는 비어있는 옵셔널이 된다.
String value = "";
Optional<String> optional = Optional.ofNullable(value);
System.out.println(optional);
value = null;
System.out.println(optional);

// 제일 위에 코드에 null을 직접 대입해보자
Optional<String> exist2 = Optional.of(null);
System.out.println(exist2);

}
}

Optional[abc]
Optional.empty
Optional[]
Optional[]
Exception in thread "main" java.lang.NullPointerException
at java.util.Objects.requireNonNull(Objects.java:203)
at java.util.Optional.<init>(Optional.java:96)
at java.util.Optional.of(Optional.java:108)
at MapExercise.Exercise1.main(Exercise1.java:27)
옵셔널 로부터 값을 갖고 오는 법
public class Exercise1 {

public static void main(String[] args) throws Exception {

String name = "James";
Optional<String> optionalName = Optional.ofNullable(name);

// String name 값이 null일경우 NoSuchElementException으로 스로우 된다
String value1 = optionalName.get();


// 값이 null일경우 공문자를 반환한다
String value2 = optionalName.orElse("");

// 값이 null일경우 람다식 결과를 반환한다
String value3 = optionalName.orElseGet(() -> {
return new SimpleDateFormat("yyyyMMddHHmmSS").format(new Date());
});

// 값이 null일경우 임의 지정 예외 처리를 한다
String value4 = optionalName.orElseThrow(() -> new Exception("값이 없습니다"));

}
}

nullpoint익셉션 에러를 피하기 위해서 옵셔널을 쓰는데..
첫번째 코드는 사실상 안쓰일것 같다..? (익섹셥이 발생하니까..)
orElse / orElseGet / orElseThrow 모두 많이 보이기 때문에 필히 익혀두자

값이 있는경우만 처리하기 !(null이 아닐때에만)
public class Exercise1 {

public static void main(String[] args) throws Exception {

String name = "James";

Optional<String> nullableName = Optional.ofNullable(name);

if (nullableName.isPresent()) {
System.out.println(nullableName.get());
} else {
System.out.println("값이 없으면 처리가 이쪽으로 빠져요");
}

String name2 = null;

Optional<String> nullableName2 = Optional.ofNullable(name2);

if (nullableName2.isPresent()) {
System.out.println(nullableName2.get());
} else {
System.out.println("값이 없으면 처리가 이쪽으로 빠져요");
}

}
}
James
값이 없으면 처리가 이쪽으로 빠져요

실무에서 쓰면 아주아주아주 유용할 기술이다

값이 있는 경우에만 람다로 처리하기
public class Exercise1 {

public static void main(String[] args) throws Exception {

String name = "James";
Optional<String> nullableName = Optional.ofNullable(name);

nullableName.ifPresent(s -> System.out.println(s));

String name2 = null;
Optional<String> nullableName2 = Optional.ofNullable(name2);

nullableName2.ifPresent(s -> System.out.println(s));
}
}

James

두번째는 null이므로 람다 처리가 되지 않았다. 이것도 실무에 쓰면 아주 유용할듯

옵셔널과 필터링의 조합

filter()메서드를 사용하면.
조건에 부합할 때 처리 / 조건에 부합하지 않으면 비어있는 옵셔널 반환 식으로 사용할 수 있다.

public class Exercise1 {

public static void main(String[] args) throws Exception {

String name = "James";
Optional<String> nullableName = Optional.ofNullable(name);

nullableName.filter(s -> s.length() > 4)
.ifPresent(p -> {
System.out.println(p);
});

nullableName.filter(s -> s.length() > 5)
.ifPresent(p -> {
System.out.println(p);
});

nullableName.filter(s -> s.length() >= 5)
.ifPresent(p -> {
System.out.println(p.toUpperCase());
});
}
}

James
JAMES
옵셔널과 map 조합으로 새로운 옵셔널에 맵핑
public class Exercise1 {

public static void main(String[] args) throws Exception {

String name = "James";
Optional<String> nullableName = Optional.ofNullable(name);

Optional<String> mappedName = nullableName.map(s -> s.toUpperCase());

mappedName.ifPresent(s -> System.out.println(s));


String name2 = null;
Optional<String> nullableName2 = Optional.ofNullable(name2);

Optional<String> mappedName2 = nullableName2.map(s -> s.toUpperCase());

mappedName2.ifPresent(s -> System.out.println(s));

}
}
JAMES

두번째는 null이므로 출력이 안된다(비어있는 옵셔널 객체)

복수의 옵셔널을 동시에 사용해보기
public class Exercise1 {

public static void main(String[] args) throws Exception {

String userName = "David";
String password = "Father";
Optional<String> nullableName = Optional.ofNullable(userName);
Optional<String> nullablePassword = Optional.ofNullable(password);

boolean isValid = nullableName.flatMap(n -> {
return nullablePassword.map(p -> {
return n.equals("David") && p.equals("Father");
});
}).orElse(false);

System.out.println(isValid);

// 한쪽에 null을 넣어봄
String idCard = null;
String cardPassword = "Brother";
Optional<String> nullableIdCard = Optional.ofNullable(idCard);
Optional<String> nullableCardPassword = Optional.ofNullable(cardPassword);

boolean getValidInform = nullableIdCard.flatMap(n -> {
return nullableCardPassword.map(p -> {
return n.equals("Joly") && p.equals("Brother");
});
}).orElse(false);

System.out.println(getValidInform);
}
}
true
false

한쪽에 null이 있을경우 비어있는 옵셔널이 반환되므로
orElse메서드의 디폴드 값인 false가 최종적으로 반환된다

실무

이분이 정말 잘 정리 해주셨다. 이분사이트를 참고하면 정말 좋은 예제를 볼 수 있다.
링크 : Java Optional바르게 쓰기

백기선님의 좋은 예제 링크 : 자바 Optional의 ifPresent활용하기

실무에서 다음과 같은 코드가 있었다.(리팩토링을 못하게 하는 현장이라 손을 댈 수 없었지만 이코드가 신경이 쓰이길래 구글링을 해봤다)

Optional<Employee> employeeData = getEmployeeData(employeeCD);

if (employeeData.isPresent()) {

Employee employee = employeeData.get();
// 조건에 따른 처리

} else {
// 조건에 따른 처리
}

위의 코드를 이렇게 바꾼다.(첫번째 링크분의 조언 - isPresent()get()대신 orElse() / orElseGet() / orElseThrow())

Optional<Employee> employeeData = getEmployeeData(employeeCD);
employeeData.orElseGet(Employee::new);
// 처리

혹은 백기선님의 조언대로 한다면 이렇게 된다

Optional<Employee> employeeData = getEmployeeData(employeeCD);
employeeData.ifPresent(employee -> {
// 처리
})