Guava의 선택적 수업의 요점은 무엇입니까


89

나는 최근에 이것에 대해 읽고이 클래스를 사용하는 사람들을 보았지만 거의 모든 경우에 사용 null하는 것도 효과적이었을 것입니다. 누군가 Optionalnull할 수 없거나 훨씬 더 깔끔한 방법으로 달성 할 수있는 구체적인 예를 제공 할 수 있습니까 ? 내가 생각할 수있는 유일한 것은 키를 Maps받아들이지 않는 것과 함께 사용하는 것입니다 null. 그러나 그것은 null 값의 사이드 "매핑"으로 수행 될 수 있습니다. 누구든지 더 설득력있는 주장을 할 수 있습니까? 감사합니다.


12
무작위로 폭언 : 사람들이 "패턴"을 남용하고 존재하지 않는 이론적 이점을 위해 코드를 너무 추하게 보이게 만드는 것이 싫습니다.
RAY

Java8에서는 JDK보다 강력하지 않기 때문에이 Guava 클래스를 더 이상 사용하지 않습니다. stackoverflow.com/a/10756992/82609
Sebastien Lorber 2014

답변:


155

구아바 팀원이 여기 있습니다.

아마도 가장 큰 단점은 null주어진 문맥에서 그것이 무엇을 의미해야하는지 명확하지 않다는 것입니다 : 설명적인 이름이 없습니다. null"이 매개 변수에 대한 값이 없음" 을 의미하는 것이 항상 분명한 것은 아닙니다 . 반환 값으로서 때로는 "오류"또는 "성공"(!!)을 의미하거나 단순히 "정답은 아무것도 아닙니다"를 의미합니다. Optional변수를 nullable로 만들 때 실제로 의미하는 개념이지만 항상 그런 것은 아닙니다. 그렇지 않은 경우 Optional실제로 의미하는 바를 명확히하기 위해 유사 하지만 다른 이름 지정 체계를 사용 하여 고유 한 클래스를 작성하는 것이 좋습니다 .

하지만 가장 큰 장점은 Optional가독성이 아니라 멍청한 증거라는 것입니다. 프로그램이 컴파일되기를 원한다면 결석 사건에 대해 적극적으로 생각해야합니다 Optional. 그 사건 을 적극적으로 풀고 해결해야하기 때문입니다. Null은 단순히 일을 잊는 것을 방해 할 정도로 쉽게 만들고 FindBugs가 도움이되지만 문제를 거의 해결하지 못한다고 생각합니다. 이는 "존재"할 수도 있고 없을 수도있는 값을 반환 할 때 특히 관련이 있습니다. 당신 (및 다른 사람들)은 구현할 때 잊을 수있는 것보다 값을 other.method(a, b)반환 할 수있는 것을 잊을 가능성이 훨씬 더 높습니다 . 복귀nullanullother.methodOptional 호출자가 개체를 직접 풀어야하므로 해당 사례를 잊을 수 없습니다.

이러한 이유로 Optional메서드에 대한 반환 유형으로 사용하는 것이 좋지만 메서드 인수에서 반드시 사용할 필요는 없습니다.

(이것은 여기 에서 논의한 내용 입니다.)


3
좋은 설명을 위해 +1. 이것이 영감인지 모르겠지만 동일한 의미를 많이 가진 SML, OCaml 및 F #의 옵션 유형에 대한 포인터를 추가합니다.
아담 Mihalcin

2
직접 관련된 사람의 답변을받는 것은 항상 좋습니다. 나는 그것을 위해 +1했을 것입니다. 훌륭한 답변을 원하시면 +1을 더하겠습니다. (하지만 그럴 수 없습니다.) 익숙하지 않은 방법의 소비자가 "아무것도"가 반환 될 수 없음을 인정하도록 강제하는 반환 값으로 갖는 것이 하나의 설득력있는 이유라고 생각합니다. 나는 그것이 어떻게 남용되고 있는지 (혹은 남용되고있는 지) 좋아하지 않는다. 예를 들어, 사람들이 옵션을지도에 값으로 넣는 것을 보면 정말 불안합니다. 존재하지 않거나 매핑되지 않은 키에 대해 null을 매핑하는 것은 잘 확립 된 패러다임입니다 ... 더 복잡하게 만들 필요가 없습니다 ...
RAY

9
그것은 잘 구축 된 사용자들은 Map리턴 null키를 매핑되지 않은,하지만 당신이 경우에 리콜 경우 map.put(key, null), 다음 map.containsKey(key)반환 true하지만 map.get(key)반환합니다 null. Optional"명시 적으로 null에 매핑 된"사례와 "지도에 없음"사례 간의 구분을 명확하게하는 데 유용 할 수 있습니다. 나는이 부여됩니다 Optional악용 될 수 있지만, 나는 아직 당신이 설명하는 경우가 남용이라고 확신 아니에요.
루이 Wasserman

8
구식 비유를 사용하기 위해 "전화 번호부"라는 거대한 것들이있었습니다. :-) 제가 누군가의 번호를 찾아 보라고했는데 "그 사람을위한 번호가 없습니다"라고 말하면 "무엇을합니까? 목록에없는 번호로 거기에 있거나 항목을 전혀 찾을 수 없습니까? " 이 두 가지 가능한 응답은 각각 Optional.absent () 및 null에 잘 매핑됩니다. Optional.absent ()는 확실한 "긍정적 부정"입니다.
Kevin Bourrillion 2012 년

3
@RAY : 어떤면에서, Optional<T> 이다 "찾았지만 유효하지 않습니다"라는 값. 더 정확하게 는 추가 "발견되었지만 유효하지 않은"값 으로 모든 유형 Optional<T>장식 하는 방법 T입니다. 기존 유형 두 개를 결합하여 새 유형을 만듭니다. 100 개의 클래스가있는 경우 각 클래스에 대해 별도의 "찾았지만 유효하지 않은"값을 만들어야하는 것은 지저분해질 수 있지만 모든 클래스에 대해 Optional<T>쉽게 작동 할 수 있습니다.
Daniel Pryden 2012 년

9

MaybeHaskell 의 Monad 패턴 처럼 보입니다 .

다음을 읽어야합니다. Wikipedia Monad (기능적 프로그래밍) :

그리고 Monad로 사용되는 Guava의 선택 사항에 대해 논의하는 Kerflyn의 블로그 에서 From Optional to Monad with Guava읽으십시오 .


편집 : Java8에는 .NET과 같은 모나 딕 연산자가있는 기본 제공 옵션이 있습니다 flatMap. 이것은 논란의 여지가있는 주제 였지만 마침내 구현되었습니다.

참조 http://www.nurkiewicz.com/2013/08/optional-in-java-8-cheat-sheet.html를

public Optional<String> tryFindSimilar(String s)  //...

Optional<Optional<String>> bad = opt.map(this::tryFindSimilar);
Optional<String> similar =       opt.flatMap(this::tryFindSimilar);

flatMap운영자는 쉽게 체인 호출 모든 반환 옵션 결과 모나드 운영 및 허가를 허용하는 것이 필수적입니다.

생각해보세요. map연산자를 5 번 사용하면으로 끝나고 Optional<Optional<Optional<Optional<Optional<String>>>>>를 사용 flatMap하면Optional<String>

Java8 이후로 덜 강력한 Guava의 Optional을 사용하지 않을 것입니다.


6

그것을 사용하는 한 가지 좋은 이유는 null을 매우 의미있게 만드는 것입니다. 많은 것을 의미 할 수있는 null을 반환하는 대신 (예 : 오류, 실패 또는 비어 있음) null에 '이름'을 넣을 수 있습니다. 이 예를보십시오 :

기본 POJO를 정의 할 수 있습니다.

class PersonDetails {

String person;
String comments;

public PersonDetails(String person, String comments) {
    this.person = person;
    this.comments = comments;
}

public String getPerson() {
    return person;
}


public String getComments() {
    return comments;
}

}

이제이 간단한 POJO를 사용해 보겠습니다.

public Optional<PersonDetails> getPersonDetailstWithOptional () {

  PersonDetails details = null; /*details of the person are empty but to the caller this is meaningless,
  lets make the return value more meaningful*/


    if (details == null) {
      //return an absent here, caller can check for absent to signify details are not present
        return Optional.absent();
    } else {
      //else return the details wrapped in a guava 'optional'
        return Optional.of(details);   
    }
}

이제 null 사용을 피하고 Optional로 확인하여 의미있는

public void checkUsingOptional () {

    Optional<PersonDetails> details = getPersonDetailstWithOptional();

    /*below condition checks if persons details are present (notice we dont check if person details are null,
    we use something more meaningful. Guava optional forces this with the implementation)*/
    if (details.isPresent()) {

      PersonDetails details = details.get();

        // proceed with further processing
        logger.info(details);

    } else {
        // do nothing
        logger.info("object was null"); 
    }

    assertFalse(details.isPresent());
}

따라서 결국 null을 의미 있고 모호하지 않게 만드는 방법입니다.


4

Optional의 가장 중요한 장점은 함수 구현 자와 호출자 간의 계약에 더 많은 세부 정보를 추가한다는 것입니다. 이러한 이유로 매개 변수와 반환 유형 모두에 유용합니다.

Optional가능한 null 개체에 대해 항상 사용하도록 규칙을 만들면 다음 과 같은 경우에 더 많은 설명을 추가합니다.

  1. Optional<Integer> maxPrime(Optional<Integer> from, Optional<Integer> to)

    여기의 계약은 결과가 반환되지 않을 가능성이 있음을 명확하게 명시하지만, 결과가 함께 작동 from하고 to부재 함을 보여줍니다 .

  2. Optional<Integer> maxPrime(Optional<Integer> from, Integer to)

    계약은 from이 선택 사항이므로 없는 값이 start from 2와 같은 특별한 의미를 가질 수 있음을 지정합니다. to매개 변수 의 null 값 이 예외를 throw 할 것으로 예상 할 수 있습니다 .

옵션을 사용하는 좋은 부분 그래서 계약 (유사한 모두 설명 된 것입니다 @NotNull당신이 코드를 작성해야하기 때문에 주석)뿐만 아니라 형식적인 .get()대처를 Optional.


빈 목록이 더 깨끗할 때 Optional <List>를 사용하는 이유는 무엇입니까?
RAY

반환에서 잘못된 예를 선택했습니다. 컬렉션을 사용하면 항상 null 값 대신 빈 컬렉션을 반환하도록 규칙을 만들 수 있습니다. 이 규칙을 사용하면 컬렉션에 대해 선택 사항이 필요하지 않습니다. 선택 사항은 0 개 또는 1 개의 요소가있는 컬렉션으로 인식 될 수 있으므로 다른 컬렉션에 배치 할 필요가 없습니다.
raisercostin

2
컨텍스트에 따라 항목이 0 개있는 목록과없는 목록간에 의미있는 차이가있을 수 있습니다.
plasma147 2014-10-21
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.