Optioinal이란?
- java8에 추가된 새로운 인터페이스
- 비어있을 수도 있고 무엇을 담을 수도 있는 컨테이너 인스턴스의 타입
public class Birthday { //생일 정보를 포함하는 클래스
private String year;
private String month;
private String day;
// ~~ getter, setter code ~~
}
public class MyName { //이름, 성별, 생일 정보를 포함하는 클래스
private Integer id;
private String name;
private boolean isMale;
public Birthday birthday; //사용자 정의 BirthDay 타입은 생성자에서 세팅해주지 않는다.
public MyName(Integer id, String name, boolean isMale){
this.id = id;
this.name = name;
this.isMale = isMale;
}
// ~~ getter, setter code ~~
}
public class App {
public static void main(String[] args) {
MyName mn = new MyName(1, "kevin", true);
String birthMonth = mn.getBirthday().getMonth();
System.out.println(birthMonth); //이 때 NullPointerException이 발생한다.
}
}
코드를 살펴보자.
MyName 클래스는 Birthday 클래스를 포함하고 있지만, 생성자에 Birthday를 파라미터로 받지 않는다.
MyName 클래스가 생성될 때 Birthday 객체는 Null 상태라는 뜻이다.
그 상태에서 Birthday 클래스의 Month 값을 가져오려고 하면 (= Null을 참조하여 어떤 메소드로 호출하려고 하면) null pointer exception이 발생한다.
// 클라이언트 단에서 null check
public class App {
public static void main(String[] args) {
MyName mn = new MyName(1, "kevin", true);
String birth = mn.getBirthday();
if(birth != null){ //null 체크하는 로직 추가
System.out.println(birth.getMonth());
}
}
}
//클래스 getter 함수에서 null check
public class MyName {
private Integer id;
private String name;
private boolean isMale;
public Birthday birthday;
// ~~ 생성자 ~~
public Birthday getBirthday() {
if(this.birthday == null) {
throw new IllegalStateException(); //null 체크하는 로직 추가
}
return birthday;
}
// ~~ 나머지 getter, setter code ~~
}
우리는 위 코드처럼 클라이언트 단 혹은 클래스 getter 함수에서 null 체크하는 로직을 추가하여 해결해왔다.
null을 리턴해주는 경우 비용 문제는 없지만 그 코드를 사용하는 클라이언트 코드에서 주의해야하고, null 체크를 누락할 경우 에러가 많이 발생할 것이다. 클래스 내에서 예외 처리를 할 경우 stacktrace를 찍기 때문에 이 자체로 리소스를 사용하게되어 비용이 많이 든다.
자바8부터는 Optional을 사용하여 더 명시적으로 표현할 수 있는 방법이 생겼다.
사용 방법
public class MyName {
private Integer id;
private String name;
private boolean isMale;
public Birthday birthday;
// ~~ 생성자 ~~
public Optional<Birthday> getBirthday() {
return Optional.ofNullable(birthday); //Optional로 감싸서 리턴한다
}
// ~~ 나머지 getter, setter code ~~
}
public class App {
public static void main(String[] args) {
MyName mn = new MyName(1, "kevin", true);
Optional<Birthday> birth = mn.getBirthday();
//Optional의 ifPresent함수 사용하여 null 체크한다
birth.ifPresent(p -> System.out.println(p.getMonth()));
}
}
위 코드와 같이 리턴할 때 Optional로 감싸서 리턴하면 된다.
(클라이언트 코드에게는 명시적으로 빈 값일 수 있따는 것을 알려주고, 빈 값인 경우에 대한 처리를 강제한다.)
Optional이라는 박스를 만든 뒤 그 안에 객체 인스턴스를 담아놓고, 박스는 비어있을 수 도 있고 값이 있을 수 도 있다.
Optional.ofNullable() 은 말 그대로 null일 가능성이 있을 때 사용하며, null이 들어올 경우 Optional이 비어있는 것과 동일하게 처리를 해준다.
Optional.of() 는 무조건 null이 아닌거라고 가정하는 함수이고, 이 때 null이 들어올 경우 null pointer exception이 발생한다.
주의할 점
- Optional은 문법적으로 제한은 없으나, 리턴 타입에만 쓰는 것만이 권장사항이다.
- 메소드 매개변수 타입으로 사용할 경우, null 체크를 또 다시 해야한다.
- 맵의 키 타입으로 사용할 경우, 맵의 정의 자체를 깨트리는 코드가 된다. 맵의 key는 null일 수 없기 때문이다.
- 인스턴스 필드 타입으로 사용할 경우, 설계의 문제이다.
- Optional을 리턴하는 메소드에서 null을 리턴하지 말 것!
- 정말 리턴할게 없다면 비어있는 Optional Optional.empty()를 리턴하자
- 프리미티브 타입용 Optional이 따로 있으니 주의하여 사용할 것 (OptionalInt, OptionalLong, ...)
- Optional.of(10); 과 같은 코드 가능하긴 하지만, 박싱/언박싱이 발생하기 때문에 권장하지 않는다.
- 컨테이너 성격의 인스턴스 Collection, Map, Stream, Array, Optional은 Optional로 감싸지 말 것'
- 그 자체로 비어있는지 판단할 수 있는 컨테이너 성격의 인스턴스들은 굳이 Optional을 쓰지 않아도 된다.
이 포스팅은 더 자바, Java 8 강의를 수강하며 작성되었습니다.
더 자바, Java 8 강의 | 백기선 - 인프런
백기선 | 자바 8에 추가된 기능들은 자바가 제공하는 API는 물론이고 스프링 같은 제 3의 라이브러리 및 프레임워크에서도 널리 사용되고 있습니다. 이 시대의 자바 개발자라면 반드시 알아야 합
www.inflearn.com
'Java' 카테고리의 다른 글
[Java8] Date & Time API (1) | 2024.08.12 |
---|---|
[Java8] Optional API (0) | 2024.08.05 |
[Java8] Stream API (0) | 2024.07.31 |
[Java8] Stream (0) | 2024.07.28 |
[Java8] Java8 API의 메소드 (0) | 2024.07.25 |