허원철의 개발 블로그

Java - Optional API 본문

java

Java - Optional API

허원철 2017. 2. 19. 15:45

이번 편은 JAVA 8에서 새롭게 등장한 Optional에 대한 간단한 예제 글 입니다.



왜 Optional을 사용해야 하는가...?


- 흔히 개발을 하다보면 null 처리에 대해 정말 난감한 부분이 많습니다. 예를 들면,


1
2
3
4
5
String name = "wonchul";
 
if(name != null && !"".equals(name)) {
    // ...
}
cs


위와 같이 조건처리가 꼭 들어가고, default value 가 필요하면 또 적당한 코드 작업이 필요합니다. 물론 유틸 클래스를 만들어서 처리 할 수 있습니다. (Spring에선 StringUtils 클래스를 제공하여 유용하게 쓸 수 있습니다.)


Optional에서는 이런 부분을 람다식 표현을 더해 조금 더 간결하고 가독성을 높일 수 있습니다. 예제는 람다식 표현과 assertj를 이용한 test code이니 참고하시고 보시면 되겠습니다.


 

Optional 생성


1
2
3
Optional<String> opName = Optional.empty();
Optional<String> opName = Optional.of("wonchul");
Optional<String> opName = Optional.ofNullable("wonchul");
cs


1) null이 들어갑니다.

2) "wonchul" 이라는 문자열을 넣습니다.

3) "wonchul" 이라는 문자열을 넣습니다.( ※ null을 넣어도 가능합니다.)



Optional get


- get() 를 이용해서 제네릭에 표기된 자료형의 값을 가져올 수 있습니다.


1
2
Optional<String> opName = Optional.of("wonchul");
opName.get(); // wonchul
cs


※ 값이 빈 경우 NoSuchElementException이 발생합니다.



Optional isPresent


- isPresent() 를 이용하여 값이 비었는지 알 수 있습니다. 


1
2
3
4
5
6
7
8
9
10
11
@Test
public void test_isParent() {
//    Optional<String> name = Optional.of("wonchul");
    Optional<String> name = Optional.ofNullable(null);
        
    if(name.isPresent()) {
        assertThat(name).isPresent();
    } else {
        assertThat(name).isNotPresent(); // call
    }
}
cs



Optional ifPresent


- ifPresent() 를 이용하여 값이 있을 경우, 원하는 처리를 할 수 있도록 도와줍니다.


1
2
3
4
5
6
@Test
public void test_ifParent() {
    Optional<String> name = Optional.of("wonchul");
    
    name.ifPresent(System.out::println); // wonchul 
}
cs



Optional isElse, isElseGet, isElseThrow


- isElseXXX() 를 이용하여 Default 처리를 하거나, exception를 보내버릴 수 있습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Test
public void test_orElse() {
    Optional<String> name         = Optional.of("wonchul");
    Optional<String> nameNullable = Optional.ofNullable(null);
        
//    ... call defaultValue()
    System.out.println("orElse      => " + name.orElse(defaultValue()));
    System.out.println("orElseGet   => " + name.orElseGet(() -> defaultValue()));
 
//    ... call defaultValue()
    System.out.println("orElse      => " + nameNullable.orElse(defaultValue()));
//    ... call defaultValue()
    System.out.println("orElseGet   => " + nameNullable.orElseGet(() -> defaultValue()));
 
//    System.out.println("orElseThrow => " + name.orElseThrow(NullPointerException::new));
}
    
private String defaultValue() {
    System.out.println("call defaultValue()");
    return "default name : wonchul";
}
cs


※ orElse, orElseGet 차이점은 defaultValue() 함수를 무조건 호출 유무에 차이입니다. defaultValue()를 호출하는데 많은 비용이 든다면, orElseGet을 이용하는 것이 더 효율적일 것 입니다. 



Example


- 오라클 기사(?)에 있는 예제를 참고한 것 입니다. (참고 : http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html


- 다음과 같은 구조에서 version을 가져올 때, 코드 작성을 예로 들어보겠습니다.



1) optional 사용하지 않은 경우


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private final String getDefaultVersion() {
    return "UNKNOWN";
}
 
@SuppressWarnings("unused")
@Test
public void test_basic() {
    Computer computer = null;
    
    String version = getDefaultVersion();
    if(computer != null) {
        if(computer.getSoundCard() != null) {
            if (computer.getSoundCard().getUsb() != null) {
                version = computer.getSoundCard().getUsb().getVersion();
            }
        }
    }
 
    assertThat(
            version
    ).isEqualTo(getDefaultVersion());
}
cs


- 중첩 if문을 사용하지 않아도 되지만, 결론적으로는 if문을 3번 사용하게 되면서 코드가 길어집니다. 


2) optional 사용한 경우


1
2
3
4
5
6
7
8
9
10
11
12
@Test
public void test_expansion() {
    Optional<OpComputer> opComputer = Optional.empty();
    
    assertThat(
            opComputer
                .flatMap(OpComputer::getSoundCard)
                .flatMap(OpSoundCard::getUsb)
                .flatMap(OpUsb::getVersion)
                .orElseGet(() -> getDefaultVersion())
    ).isEqualTo(getDefaultVersion());
}
cs


- flatMap과 orElseGet를 조합하여 깔끔한 코드를 만들어낼 수 있습니다.


※ JAVA 8부터는 유용한 메소드가 많습니다. ( filter, steam, flatmap, map.. 등등 ) 여러 조합으로 섞어쓰면 기존에 JAVA 8미만에서의 코드보다 가독성이 높은 코드를 만들 수 있습니다.



참고


http://www.oracle.com/technetwork/articles/java/java8-optional-2175753.html

- Java8OptionalAPI

'java' 카테고리의 다른 글

Java - Compare GC  (406) 2017.03.07
Java - GC (Garbage Collection)  (420) 2017.03.05
Java - time package(LocalTime, LocalDate, LocalDateTime,...)  (398) 2017.02.07
Java - JUnit & AssertJ  (406) 2016.12.05
Java - Stream API  (404) 2016.12.05
Comments