일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 오라클
- 프로그래머스
- 매핑
- math
- 알고리즘
- spring
- 카카오톡1차
- JPA
- Head First Design Pattern
- Oracle
- javascript
- 디자인패턴
- 인프런
- 공부
- 인강리뷰
- Singleton
- 회고
- 이펙티브자바
- 우아한테크코스
- 인코딩
- 에러
- Design Pattern
- study
- 람다
- Java
- 독서리뷰
- 독서
- 자바
- Eclipse
- 후기
- Today
- Total
Lee's Grow up
[자바/Java] Optional 개념, 사용 본문
해당 내용은 책 모던 자바 인 액션
의 내용을 참고해서 작성하였습니다.
등장 배경
Java를 통해 개발을 진행하다 보면, 해당 객체의 참조 값이 null
인지 아닌지 체크하는 분기문이 생기는데, 이와 같은 분기문의 경우 코드의 가독성이 떨어지고, 해당 객체가 null
을 가질 수 있는 객체인지, 필수 값인지 직관적으로 알 수 있는 방법이 없어서 에러의 근원이 되는 문제가 발생했기 때문에, 선택형값을 캡슐화하는 클래스 Optional
을 Java 8에 추가되었다.
Optional 객체 만들기
1. 빈 Optional 객체 만들기
Optionl
클래스의 정적 팩토리 메소드로 아래와 같이 사용 가능
Optional<String> optStr = Optional.empty();
2. null이 아닌 값으로 Optional 만들기
만약 값이 null이라면 바로 NullPointException
이 발생하며, 값을 항상 넘겨줘야 한다.
Optional<String> optStr = Optional.of("not null");
3. null 허용 Optional 만들기
null또는 값을 가질 수 있는 Optional을 리턴해준다.
Optional<String> optStr = Optional.ofNullable(null);
Optional 클래스의 메서드
예제를 위해 사용되는 클래스는 아래와 같다.
public class Person {
private Car car;
private int age;
public Optional<Car> getCar(){ return Optional.ofNullable(car); }
public int getAge() { return age; }
}
public class Insurance {
private String name;
public String getName() { return name; }
}
public class Car {
private Insurance insurance;
public Optional<Insurance> getInsurance(){ return Optional.ofNullable(insurance); }
}
위와 같은 도메인 모델이 구성되어 있을 때, Car
을 기준으로 보면 getCar
은 Optional을 리턴하고 getAge
는 int형을 리턴해준다. 이렇게 한눈으로 값이 꼭 있어야 하는지, null이 들어갈 수 있는 객체인지 여부를 구체적으로 표현할 수 있는 장점이 있게된다. 또 특이한점은 필드로 옵셔널 객체 즉 private Optional<Car> car
과 같은 방식을 사용하지 않은 이유는 해당 클래스를 설계한 사람이 용도를 선택형 반환값으로 구분을 지었기 때문에 Serializable
를 구현하지 않았다. 그래서 직렬화가 필요한 프레임워크나, 도구에서 문제가 생길 수가 있기 때문이다.
메서드의 종류
1. empty, of, ofNullable
Optional 인스턴스를 반환 각각 빈 옵셔널, 널이 아닌 옵셔널, 널을 허용하는 옵셔널 ( 위에 설명이 있기 때문에 생략 )
2. filter
마치 스트림처럼 피리디케이트와 일치하면 값을 포함한 Optional<T>
을 리턴, 없으면 empty
옵셔널을 리턴해준다.
Optional.of(new Person()).optPerson.filter(p -> p.getAge() > 19);
위와 같이 사용가능하며, 나이가 19세를 넘어가는 Person인지 필터가 가능하다.
3. map
스트림과 비슷하며, 존재하면 값이 존재하면 매핑 함수를 적용
Optional<String> name =
Optional.of(new Insurance()).map(Insurance::getName);
Optional<Optional<Car>> optCar =
Optional.of(new Person()).map(Person::getCar);
2개의 map
을 사용했으며, optCar
의 경우 반환 타입이 옵셔널 안에 옵셔널이 감싸지는 형태로 리턴이 된다. 이유는 Optional.map
자체가 해당 값을 옵셔널로 감싸주는 메서드인데, Person.getCar
의 경우 리턴 타입이 Optional<Car>
이기 때문이다. 이와 같은 문제로 인해, 바로 아래 flatMap
메서드를 제공해준다.
4. flatMap
스트림과 비슷, 평면화를 위해 사용. 값이 존재하면 제공된 함수를 적용한 결과를 값을 포함한 Optional<T>
을 리턴, 없으면 empty
옵셔널을 리턴해준다.
Optional<Insurance> optInsurancer =
Optional.of(new Person())
.flatMap(Person::getCar)
.flatMap(Car::getInsurance);
5. get
Optional이 감싸고 있는 값을 반환하고, 값이 없으면 NoSuchElementException
발생
Optional.empty().get();
위에는 빈 옵셔널에 get
메서드를 호출하기 때문에 NoSuchElementException
이 발생한다.
6. isPresent
값이 존재하면 true, 빈 옵셔널이면 false
Optional.ofNullable(null).isPresent();
Optional.ofNullable("not null").isPresent();
위 첫번 째 결과는 false
, 두번째는 true
를 반환
7. ifPresent ,ifPresentOrElse
ifPresent
의 경우 값이 존재하면 지정된 Consumer
를 실행하고, 없으면 아무동작도 안함
ifPresentOrElse
은 java 9에 추가 되었으며, 추가로 Runnable
인터페이스를 넘겨준다. 값이 존재하면 지정된 Consumer
를 실행하고, 값이 없으면 넘겨받은 Runnable
를 실행
// 첫번째 실행 안하고 not null만 출력
Optional.ofNullable(null).ifPresent(System.out::println);
Optional.ofNullable("not null").ifPresent(System.out::println);
// 무언가동작, not null 2개의 문장 출력
Optional.ofNullable(null).ifPresentOrElse(System.out::println, () -> System.out.println("무언가 동작"));
Optional.ofNullable("not null").ifPresentOrElse(System.out::println, () -> System.out.println("무언가 동작"));
8. or
값이 존재하면 같은 Optional<T>
을 리턴, 없으면 Supplier
에서 만든 Optional<T>
을 리턴
Optional.ofNullable(null).or(() ->(Optional.of("UnKnown")));
Optional.ofNullable("not null").or(() ->(Optional.of("UnKnown")));
각각 Optional<String>
를 리턴해주며, 첫번째는 "UnKnown"이라는 값을 가진 옵셔널을 두번째는 "not null"이란 값을 가진 옵서녈을 리턴해준다.
9. orElse
값이 존재하면 값을 리턴, 없으면 인자로 제공된 기본값을 반환
Optional.ofNullable(null).orElse("UnKnown");
or
메서드와 다르게 바로 값을 반환해주며 해당 예제는 String 타입의 "UnKnown"을 리턴해준다
10. orElseGet
값이 존재하면 값을 리턴, 없으면 Supplier
에서 제공되는 값을 반환
Optional.ofNullable(null).orElseGet(() -> new String("UnKnown"));
11.orElseThrow
값이 존재하면 값을 리턴, 없으면 Supplier
에서 생성한 예외를 발생
Optional.ofNullable(null).orElseThrow(NullPointerException::new);
예제에서는 NullPointException
을 사용했는데, 이러면 Optional
을 사용하는 의미가 없기 때문에, 필요하다면 사용자 정의 Exception 또는 기존에 정의된 Exception중 필요한걸 찾아서 넘겨주면 된다.
12. stream
값이 존재하면 존재하는 값만 포함하는 스트림을 반환하고, 없으면 empty 스트림 반환
Optional.ofNullable(null).stream();
기본형 특화 옵셔널
스트림처럼 기본형 int, long, double 전용 옵셔널이 존재하지만. 스트림의 경우 요소가 여러개이기 때문에 오토박싱에 대한 비용을 감소시켜서 성능 향상의 효과가 있었지만, 옵셔널의 경우 요소의 수는 한개이므로 성능향상은 존재하지 않는다. 또한 map
, flatMap
, fillter
등을 지원해주지 않고, 기존의 Optional
과 혼용으로 사용이 불가능 하기 때문에 기본형 특화 옵셔널 사용을 하지 말아야 한다.
'PROGRAMMING > JAVA' 카테고리의 다른 글
[Java/java] 스트림과 컬렉터 Stream, Collector (0) | 2020.05.26 |
---|---|
[자바/Java] Lambda 람다 표현식, 함수형 인터페이스 (0) | 2020.05.22 |
[Java/자바] 람다의 사용, 동작을 파라미터화 (0) | 2020.05.21 |
[자바/java] 지네릭스 & 와일드 카드 (0) | 2020.05.15 |
[JAVA/JPA] 값 타입 (0) | 2020.04.13 |