본문 바로가기

JAVA/JAVA 객체지향

[Java] Optional 클래스

Optional 클래스란?

Optional <T> 제네릭 클래스로 "T타입의 객체" 감싸는 래퍼 클래스.

Optional타입의 객체에는 모든 타입의 참조변수를 담을 있습니다.

 

Optional클래스는 모든 객체를 감싸기 때문에 Null인지 아닌지 일일이 확인하지 않아도 Optional 정의된 메서드를 통해서 간단히 처리 가능합니다.

 

if문으로 체크하지 않아도 NullPointException 발생하지 않게 간결하고 안전한 코드를 작성 가능합니다.

 

NullPointerException 예외 발생 상황

class Friend{
    String name;
    Company cmp;
    public Friend(String n, Company c){
        name = n;
        cmp = c;
    }
    public String getName(){
        return name;
    }
    public Company getCmp(){
        return cmp;
    }
}

class Company{
    String cName;
    ContInfo cInfo;
    public Company(String cn, ContInfo ci){
        cName = cn;
        cInfo = ci;
    }
    public String getCName(){
        return cName;
    }
    public ContInfo getCInfo(){
        return cInfo;
    }
}

class ContInfo{
    String phone;
    String adrs;
    public ContInfo(String ph, String ad){
        phone = ph;
        adrs = ad;
    }
    public String getPhone(){
        return phone;
    }
    public String getAdrs(){
        return adrs;
    }
}
 

 

친구 정보를 저장하고, 참조할 있는 프로그램을 만들었다고 가정합니다.

Friend 클래스는 친구의 이름(name) 회사(Company) 저장할 있도록 작성 되었습니다.

하지만 직장이 없는 친구들도 있을 있습니다. 이럴 경우 회사 정보는 null 것 입니다.

null 경우 NullPointException 발생하지 않도록 if문으로 처리 할 있습니다.

public void showCompAddr(Friend friend) {
        String addr = null;
        if (friend != null) {   //인자 null 확인
            Company com = friend.getCmp();
            if (com != null) {  //회사정보 확인
                ContInfo contInfo = com.getCInfo();
                if (contInfo != null) { //연락처 정보 확인
                    addr = contInfo.getAdrs();
                }
            }
        }
        if(addr != null) {// 위의 코드에서 주소 정보를 얻지 못했을 수 있으니 검증
            System.out.println(addr);
        }else{
            System.out.println("There's no address information.");
        }
    }
 

null 경우 if문으로 모든 처리를 하게 작성된 코드입니다.

이러한 코드는 가독성도 떨어진 뿐만 아니라 유지 보수 측면에서도 어려운 코드입니다.

이를 해결하기 위해서 등장한 것이 Optional 클래스입니다.

 

Optional클래스의 기본적인 사용 방법

Optional클래스는 일종의 래퍼(Wrapper) 클래스입니다.

래퍼 클래스가 기본 자료형을 담아 클래스로 표현하듯이, Optional클래스에 객체를 담아 null 허용할 도있고, 허용하지 않을수도 있습니다.

        Optional<String> os1 = Optional.of(new String("테스트1"));
        Optional<String> os2 = Optional.ofNullable(new String("테스트2"));
 
        if(os1.isPresent())
            System.out.println(os1.get());
        if (os2.isPresent())
            System.out.println(os2.get());
 
        os1.ifPresent(s -> System.out.println(s));
        os2.ifPresent(System.out::println);

 

of()

null을 허용하지 않는다.

ofNullable()

null을 허용한다.

isPresent()

객체가 있는지 없는지 확인한다. 있으면 treu 없으면 false

ifPresent()

객체가 있으면 객체를 전달, 없다면 전달하지 않는다.

get()

Optional 클래스 안에 있는 객체를 꺼내온다.

Optional 클래스로 if~else 문을 대신하기

 
        Optional<String> os3 = Optional.of("Optional String");
        Optional<String> os4 = os3.map(s -> s.toUpperCase());
        System.out.println(os4.get());
 
        Optional<String> os5 = os3.map(s -> s.replace(' ''_'))
                                  .map(s -> s.toUpperCase());
        System.out.println(os5.get());
 

map() 메서드는 Optional 클래스 안에 있는 인스턴스를 가져와 처리한 뒤에 다시 Optional 인스턴스로 반환해 줍니다.

os4 참조변수는 os3 참조변수의 Optional클래스에서 인스턴스를 가져와("Optional String") 대문자로 변경해 주고 다시 Optional클래스의 인스턴스로 반환해 줍니다.

os5 참조변수도 마찬가지로 os3 참조변수의 Optional클래스에서 인스턴스를 가져와 공백대신에 '_' 치환한 대문자로 변경해주고 Optional클래스의 인스턴스로 반환해 줍니다.

 

flatMap()메서드

        //map()메서드
        Optional<String> os1 = Optional.of("Optional String");
        Optional<String> os2 = os1.map(s -> s.toUpperCase());
        System.out.println(os2.get());
        
        //flatMap()메서드
        Optional<String> os3 = os1.flatMap(s -> Optional.of(s.toLowerCase()));
        System.out.println(os3.get());
 

flatMap()메서드는 map() 메서드와 같지만 다른 한가지가 있습니다.

flatMap()메서드는 반환하는 인스턴스 자료형 그대로 반환하는 것입니다.

위에 코드에서 os1.flatMap()메서드는 map()메서드와 다르게 Optional.of()메서드로 감싸서 반환해 주고 있습니다.

 

map()

Optional클래스에서 반환 된 객체를  map() 매서드의 매개변수로 전달 다시 Optioanl 인스턴스로 감싸서 반환한다.

flatMap()

Optional 클래스에서 반환 된 객체를 map() 매서드의 매개변수로 전달 한 뒤 매개변수 그대로 반환한다.

Optional<String> os6 = Optional.empty();
        Optional<String> os7 = Optional.of("테스트");
        String s1 = os6.map(s -> s.toString())
                .orElse("Empty");
        String s2 = os7.map(s -> s.toString())
                .orElse("Empty");
        System.out.println(s1);
        System.out.println(s2);

orElse() 메서드는클래스가 반환하는 객체가 없다면 orElse()메서드에서 정의한 것이 대신 반환 됩니다.

 

orElse()

Optional클래스에서 반환되는 객체가 있다면 객체를 전달 없다면 orElse() 호출하면서 전달된 인스턴스가 대신 반환된다.

showCompAddr 메서드의 개선 결과

 public void showCompAddr(Friend friend) {
        String addr = null;
        if (friend != null) {   //인자 null 확인
            Company com = friend.getCmp();
            if (com != null) {  //회사정보 확인
                ContInfo contInfo = com.getCInfo();
                if (contInfo != null) { //연락처 정보 확인
                    addr = contInfo.getAdrs();
                }
            }
        }
        if(addr != null) {// 위의 코드에서 주소 정보를 얻지 못했을 수 있으니 검증
            System.out.println(addr);
        }else{
            System.out.println("There's no address information.");
        }
    }
 

위에서 NullPointException이 발생하지 않게 하기 위해 if문으로 처리한 메서드를 Optional클래스로 바꿀 수 있습니다.

 public static void main(String[] args){
        ContInfo contInfo = new ContInfo("010-1111-2222""서울시 강남구");
        Company company = new Company("hunda., Ltd", contInfo);
        Friend friend = new Friend("LEE", company);
        showCompAddr(Optional.of(friend));
    }

    public void showCompAddr(Optional<Friend> friend) {
        String addr = friend.map(Friend::getCmp)
                .map(Company::getCInfo)
                .map(ContInfo::getAdrs)
                .orElse("There's no");
        System.out.println(addr);
    }
}
 

Optioanl클래스로 변경된 코드

 


윤성우의 열혈 JAVA - https://cafe.naver.com/cstudyjava?iframe_url=/MyCafeIntro.nhn%3Fclubid=19799898