본문 바로가기

프로그래밍/자바

[자바/기본] Optional 이란?

728x90
반응형
SMALL

Optional 이란?

  • 자바의 가장 큰 고질적인 문제가 바로 null 체크 였다고 한다.
    • 이를 해결하기 위해 값이 1개 있거나 없을 수 있는 클래스를 만듦
  • Java8부터 지원하는 Optional 클래스
  • NPE (NullPointer Exception) 를 피하기 위해 Null 값을 감쌀 수 있는 Wrapper Class 이다.
    • Optional<T>
class Optional<T> {
	T value;
    ....
}

 


Optional 없는 NullCheck

  • 아래와 같은 User 클래스가 있다.
public class User {
	private String address;

	public String getAddress() {
		return this.address;
	}

	public void setAddress(String address) {
		this.address = address;
	}
}

 

  • 만약 User 객체에서 address를 접근하고자 할때, 객체가 null 인 경우를 배제 할 수 없다.
User user = getUser();
String address = user.getAddress()	// 만약 유저가 null 이라면 NPE 발생

//null 체크하는 코드
if(user != null) {
	if(address != null){
    	address = user.getAddress()
    }
}

 

  • 위와 같은 방법으로 null 체크를 해야하고 null체크를 하면서 코드가 조금 지저분해진 느낌을 받을 수 있다.
    • 또한, address가 String이 아닌 또 하나의 클래스였고 그 안에 또 멤버 변수들이 있었다면 null 체크는 더 복잡해 졌을 것으로 보여진다.

Optional 생성 메소드

  • Optional.of(value) : value 가 null이면 NPE 발생
  • Optional.ofNullable(value) : value 가 null이면 empty Optional 생성
  • Optional.empty() : empty Optional 생성
	   String str = "hello";
       Optional<String> o1, o2, o3;
       
       // 1. Optional.of(value) 를 사용하여 생성
       o1 = Optional.of(str);
       System.out.println(o1);  // Optional[hello]
       System.out.println(o1.get());  // "hello"

//     o1 = Optional.of(null); // of(value) 의 value 가 null이면 NPE 발생

       // 2. Optional.ofNullable(value)
       // value 가 null이면 empty Optional 객체 반환
       o2 = Optional.ofNullable(str);
       System.out.println(o2);
       System.out.println(o2.get());
       o2 = Optional.ofNullable(null);  // null 가능!
       System.out.println(o2);  // Optional.empty
       //System.out.println(o2.get());   // 에러 NoSuchElementException: No value present

       
       // 3.Optional.empty()  empty Optional 객체 반환
       o3 = Optional.empty();
       System.out.println(o3);  // Optional.empty

 

  • 위와 같은 3가지 방법으로 Optional  생성 할 수 있다.

More

  • 만약 담아야 하는 값들이 기본 자료형이고 이를 위해 Wrapper 클래스를 사용해야 한다면
    • EX) Optional<Integer>, Optional<Long>
  • 위의 예시 처럼 사용하지 말고
    • OptionalInt, OptionalLong 등을 사용할 수 있다.
Optional<Integer> optInteger = Optional.of(10);  // boxing 발생
OptionalInt optInt = OptionalInt.of(10);  // boxing 발생 안함.
OptionalLong optLong = OptionalLong.of(1234L);
OptionalDouble optionalDouble = OptionalDouble.of(3.14);

System.out.println(optInteger.get() + 0);  // unboxing 발생
System.out.println(optInt.getAsInt() + 0);  // unboxing 발생 안함.
System.out.println(optionalDouble.getAsDouble());
System.out.println(optLong.getAsLong());

 


Optional 주요 메소드

주요 메소드
isPresent() boolean 내부 객체가 null 인지 아닌지 확인

null 이면 false 반환
ifPresent(Consumer<T>) void Consumer<T>는 함수형 인터페이스로 void 추상 메소드를 가지고 있으며, null이 아닐 때만 실행
filter(Predicate<T>) Optional<T> 내부 객체가 Predicate<T>(리턴 타입 boolean)를 만족 하는지 확인
map(Functional<T, U>) Optional<U> stream과 같이 내부 객체를 변환 하는 용도로 사용한다.
get() T 내부 객체를 반환한다. 내부 객체가 null 이면 NPE
null 이 아닌 경우에만 사용해야한다.
orElse(T) T 내부 객체를 반환 하고, 내부 객체가 null 이면 인자로 들어간 기본값을 반환한다.
orElseGet(Supplier<T>) T  orElse() 와 동일하지만  orElseGet()은 내부 객체가 null 일때 기본 값을 반환할 객체를 인자로 받는다.
orElseThrow(Supplier<U>) T 내부 객체가 null 이면 인자로 전달받은 예외를 발생 시킨다.

 

public class Address {
    private String street;

    public Address(){}
    public Address(String street) {
       this.street = street;
    }

    public String getStreet() {
       return street;
    }

    public void setStreet(String street) {
       this.street = street;
    }

    @Override
    public String toString() {
       return String.format("[Address: street=%s]", this.street);
    }
}

 

 

  • 위와 같은 클래스가 있을 때, Optional 클래스를 어떻게 사용 할 수 있는 지 사용해 보도록 하겠다.
	Address addr1 = new Address("역삼로");
       Address addr2 = null;
       Optional<Address> optAddr1, optAddr2;
       
       //생성할 때, of() 안에 null 이면 NPE
//     optAddr2 = Optional.of(addr2);  // NPE 발생
       optAddr2 = Optional.ofNullable(addr2);	//Optional.Empty 생성

		
       System.out.println(optAddr2.isEmpty());  // true
       System.out.println(optAddr2.isPresent()); // false

       optAddr1 = Optional.of(addr1);
       System.out.println(optAddr1.isEmpty());  // false
       System.out.println(optAddr1.isPresent());  // true

       optAddr1.ifPresent(s -> System.out.println("주소:" + s));
       optAddr1.ifPresent(s -> System.out.println(s));
       optAddr1.ifPresent(System.out::println);

       System.out.println(optAddr1.get());
       // System.out.println(optAddr2.get()); // // NoSuchElementException 발생

       System.out.println(optAddr1.orElse(new Address("UNKNOWN")));  // orElse(T)
       System.out.println(optAddr2.orElse(new Address("UNKNOWN")));
       System.out.println(optAddr2.orElseGet(() -> new Address("몰라요")));

//     optAddr2.orElseThrow(); // NoSuchElementException 발생
//     optAddr2.orElseThrow(() -> new NullPointerException());

       System.out.println(optAddr1.filter(s -> s.getStreet().equals("역삼로")));
       System.out.println(optAddr1.filter(s -> s.getStreet().equals("강남대로")));  // Optional.empty

       System.out.println(optAddr1.map(s -> s.getStreet().length()));	//Optional[3]

 

 

Optional 클래스가 지원하는 메소드들을 통해 Java에서 객체의 null 체크를  방법들에 대해서 정리 하였다.

728x90
반응형
LIST