IT이야기

옵션에서의 사용

cyworld 2022. 7. 5. 22:19
반응형

옵션에서의 사용

Java 8을 사용한 지 6개월 정도 되었기 때문에 새로운 API 변경에 매우 만족하고 있습니다.아직 자신 없는 부분은 언제 사용할 것인가 하는 것입니다.Optional어디에나 사용하고 싶은지 망설여지는 것 같다.null어디에도 없습니다.

사용할 수 있는 상황도 많은 것 같고, 장점(가독성/안전성)이 추가되는지, 오버헤드만 추가되는지는 잘 모르겠습니다.

몇 가지 예를 들어보죠 지역사회의 생각을 들어보고 싶은데요Optional유익합니다.

1 - 메서드가 반환될 수 있는 경우 공개 메서드 반환 유형으로 지정null:

public Optional<Foo> findFoo(String id);

2 - 매개 변수가 다음과 같은 경우 메서드 매개 변수로서null:

public Foo doSomething(String id, Optional<Bar> barOptional);

3 - 콩의 옵션 구성원으로서:

public class Book {

  private List<Pages> pages;
  private Optional<Index> index;

}

4 - 입력Collections:

일반적으로는 다음과 같이 생각하지 않습니다.

List<Optional<Foo>>

무엇이든 추가할 수 있습니다.특히 사용할 수 있기 때문에filter()제거하다null가치 등입니다만, 좋은 용도가 있습니까?Optional콜렉션으로요?

내가 놓친 사건이라도 있나?

주요 설계 목표Optional는 반환값의 부재를 나타내는 값을 반환하는 함수를 위한 수단을 제공하는 것입니다.이 설명을 참조해 주세요.이것에 의해, 발신자는 일련의 유창한 메서드콜을 계속할 수 있습니다.

이는 OP 질문의 사용 사례 1과 가장 밀접하게 일치합니다.단, 값의 부재null보다 더 정확한 공식입니다.IntStream.findFirstnull을 반환할 수 없습니다.


사용 사례 #2의 경우, 선택적 인수를 메서드에 전달하면 효과가 있을 수 있지만, 다소 서툴러집니다.예를 들어 문자열 뒤에 옵션의 두 번째 문자열을 사용하는 메서드가 있다고 가정합니다.승인하다Optional두 번째 arg는 다음과 같은 코드가 됩니다.

foo("bar", Optional.of("baz"));
foo("bar", Optional.empty());

null을 받아들이는 것이 더 좋습니다.

foo("bar", "baz");
foo("bar", null);

아마도 가장 좋은 방법은 단일 문자열 인수를 받아들여 두 번째 문자열에 대한 기본값을 제공하는 오버로드 메서드를 사용하는 것입니다.

foo("bar", "baz");
foo("bar");

이것은 제한이 있지만, 위의 어느 것보다도 훨씬 좋습니다.

사용 사례 #3 및 #4는 다음과 같습니다.Optional클래스 필드 또는 데이터 구조에서 API의 오용으로 간주됩니다.첫째, 이는 주요 설계 목표인Optional상부에 기재된 바와 같이둘째, 아무런 가치도 없습니다.

가치의 부재를 처리하는 방법에는 세 가지가 있습니다.Optional: 대체값을 제공하거나 함수를 호출하여 대체값을 제공하거나 예외를 발생시킵니다.필드에 저장하는 경우 초기화 또는 할당 시 이 작업을 수행합니다.OP에서 설명한 바와 같이 값을 목록에 추가할 경우 값을 추가하지 않고 부재 값을 "평활화"할 수 있습니다.

누군가 정말로 보관하고 싶은 계획적인 사건들을 생각해 낼 수 있을 거예요Optional필드나 컬렉션에 포함되지만 일반적으로 이 작업은 피하는 것이 좋습니다.

나는 게임에 늦었지만, 그것이 가치가 있는 것을 위해, 나는 나의 2센트를 추가하고 싶다.Stuart Marks의 답변으로 잘 요약되어 있는 설계 목표에 어긋나지만, 저는 여전히 그 타당성을 확신하고 있습니다(분명히).

어디서나 옵션 사용

일반

블로그 투고 전체를 썼는데, 요점은 다음과 같습니다.

  • 가능한 한 옵션성을 회피하도록 클래스를 설계한다.
  • 나머지 모든 경우 디폴트는 다음과 같습니다.Optional대신null
  • 다음과 같은 경우에 예외를 둘 수 있습니다.
    • 지역 변수
    • 값과 인수를 개인 메서드로 되돌리다
    • 퍼포먼스 크리티컬코드 블록(추측 없음, 프로파일러 사용)

처음 두 가지 예외는 참조의 래핑 및 래핑 해제에 대한 인식 오버헤드를 줄일 수 있습니다.Optionalnull이 합법적으로 어떤 인스턴스에서 다른 인스턴스로 경계를 통과할 수 없도록 선택됩니다.

주의: 이것은, 거의 모든 것을 허가하지 않습니다.Optionals는 거의 와 같은 불량인 컬렉션에 포함되어 있습니다.nulls. 그냥 하지 마세요.;)

질문하신 내용에 대해서

  1. 네.
  2. 오버로드가 선택사항이 아닌 경우 그렇습니다.
  3. 다른 접근법(서브클래싱, 장식 등)이 선택사항이 아닌 경우에는 그렇습니다.
  4. 제발 안 돼요!

이점

이를 통해 의 존재감이 감소합니다.null코드 베이스에 있습니다.다만, 삭제는 행해지지 않습니다.하지만 그것은 심지어 요점이 아니다.기타 중요한 장점이 있습니다.

목적의 명확화

사용.Optional변수가 선택 사항임을 명확히 표현합니다.코드 리더나 API의 소비자는 아무것도 없을 수 있으며 값에 액세스하기 전에 확인이 필요하다는 사실에 충격을 받게 됩니다.

불확실성 제거

없이.Optional의 의미null발생이 불분명하다.스테이트의 법적 표현(을 참조), 또는 초기화 누락이나 실패 등의 실장 에러일 가능성이 있습니다.

이는 의 지속적인 사용에 따라 극적으로 변화합니다.Optional여기에서는, 이미 의 발생이 있습니다.null버그의 존재를 나타냅니다.(값이 누락되어 있는 경우,Optional사용되었을 것입니다.)이것에 의해, null 포인터 예외의 디버깅이 한층 더 용이하게 됩니다.null는 이미 응답되어 있습니다.

기타 특수한 체크

이제 아무것도 할 수 없으니null더 이상 어디서든 시행될 수 있어요주석, 어설션 또는 플레인 체크의 경우 이 인수 또는 반환 유형이 null일 수 있는지 여부를 고려할 필요가 없습니다.안 돼!

단점들

물론 은탄은 없지만...

성능

값(특히 기본 값)을 추가 인스턴스로 래핑하면 성능이 저하될 수 있습니다.꽉 막힌 루프에서는 이것이 눈에 띄거나 더 나빠질 수 있습니다.

컴파일러는 단수명에 대한 추가 참조를 회피할 수 있습니다.Optionals. Java 10에서는 값 유형이 패널티를 더 줄이거나 제거할 수 있습니다.

시리얼화

Optional 는 시리얼화할 수 없지만 회피책은 그다지 복잡하지 않습니다.

불변성

Java에서는 범용 타입의 불변성으로 인해 실제 값 타입이 범용 타입 인수에 푸시되면 특정 조작이 번거로워집니다.여기에 예가 나와 있습니다("모수 다형성" 참조).

개인적으로 인텔리J의 코드 검사 도구를 사용하여@NotNull그리고.@Nullable체크는 주로 컴파일 시간이기 때문에 (일부 런타임체크를 할 수 있습니다)코드 가독성과 런타임 성능 측면에서 오버헤드가 낮습니다.Optional을 사용하는 것만큼 엄격하지는 않지만, 이러한 엄격함의 결여는 적절한 장치 테스트를 통해 뒷받침되어야 합니다.

public @Nullable Foo findFoo(@NotNull String id);

public @NotNull Foo doSomething(@NotNull String id, @Nullable Bar barOptional);

public class Book {

  private List<Pages> pages;
  private @Nullable Index index;

}

List<@Nullable Foo> list = ..

이 기능은 Java 5에서 작동하며 값을 랩 또는 언랩할 필요가 없습니다.(또는 래퍼 오브젝트 작성)

Guava Optional과 Wiki 페이지에는 다음과 같은 내용이 게재되어 있습니다.

null 이름을 붙임으로써 가독성이 향상되는 것 외에 Optional의 가장 큰 장점은 백치 방지입니다.Optional(옵션)을 액티브하게 전개해, 그 케이스에 대처할 필요가 있기 때문에, 프로그램을 컴파일 하고 싶은 경우는, 부재 케이스에 대해 적극적으로 생각할 필요가 있습니다.Null은 단순히 잊어버리는 것을 불안하게 쉽게 만들고, FindBugs는 도움이 되지만, 우리는 그것이 이 문제를 거의 해결한다고 생각하지 않는다.

이는 "존재할 수도 있고 없을 수도 있는" 값을 반환할 때 특히 중요합니다.other.method(a, b)가 null 값을 반환할 수 있다는 것을 잊어버릴 가능성이 other.method를 실장할 때 a가 null일 수 있다는 것을 잊어버릴 가능성이 매우 높습니다.[선택사항]을 반환하면 발신자는 코드를 컴파일하기 위해 오브젝트를 직접 언랩해야 하므로 이 케이스를 잊어버릴 수 없습니다.-- (출처:Guava Wiki - null 사용 및 회피 - 요점이 무엇입니까?

Optional오버헤드를 조금 더하지만 오브젝트가 없을 수 있다는 것을 명확히 하고 프로그래머가 상황을 처리하도록 하는 것이 분명한 장점이라고 생각합니다.사랑하는 사람을 잊는 것을 방지한다.!= null확인.

2의 예를 들어, 나는 훨씬 더 명확한 코드를 쓰는 것이라고 생각한다.

if(soundcard.isPresent()){
  System.out.println(soundcard.get());
}

보다

if(soundcard != null){
  System.out.println(soundcard);
}

저 같은 경우에는Optional는 사운드 카드가 존재하지 않는다는 사실을 보다 잘 포착합니다.

당신의 요점에 대한 나의 2가지 질문:

  1. public Optional<Foo> findFoo(String id);- 이건 잘 모르겠어요.아마도 나는 반환할 것이다.Result<Foo>비어 있을 수도 있고, 포함되어 있을 수도 있습니다.Foo비슷한 개념이지만, 실제로는 그렇지 않습니다.Optional.
  2. public Foo doSomething(String id, Optional<Bar> barOptional);- Peter Lawrey의 답변처럼 @Nullable과 findbugs 체크를 선호합니다 - 이 토론도 참조하십시오.
  3. 책의 예 - 복잡도에 따라 달라질 수 있으므로 내부적으로 Optional을 사용할지 확신할 수 없습니다.책의 'API'를 위해, 저는 'API'를 사용합니다.Optional<Index> getIndex()책에 색인이 없을 수 있음을 명시적으로 나타냅니다.
  4. 컬렉션에서 사용하지 않고 컬렉션에서 null 값을 허용하지 않습니다.

일반적으로, 나는 주변으로 가는 것을 최소화하려고 노력할 것이다.nulls. (일단 구워지면...) 적절한 추상화를 찾아 동료 프로그래머에게 어떤 반환값이 실제로 무엇을 나타내는지 알려주는 것이 가치가 있다고 생각합니다.

Oracle 튜토리얼에서:

Optional의 목적은 코드베이스 내의 모든 null 참조를 대체하는 것이 아니라 메서드의 시그니처를 읽는 것만으로 사용자가 옵션 값을 기대할 수 있는지 여부를 판단할 수 있는 보다 나은 API를 설계하는 것입니다.또한 [Optional]를 사용하면 값의 부재를 처리하기 위해 [Optional]를 적극적으로 언랩할 수 있습니다.그 결과 의도하지 않은 늘 포인터의 예외로부터 코드를 보호할 수 있습니다.

자바에서는 기능 프로그래밍에 중독되지 않는 한 사용하지 마십시오.

메서드 인수는 없습니다(언젠가는 비어 있는 옵션뿐만 아니라 늘옵션을 전달할 것을 권장합니다).

반환값은 타당하지만 동작 빌드 체인을 계속 확장하도록 클라이언트클래스를 초대합니다.

FP와 체인은 Java와 같은 명령어에서는 읽기뿐만 아니라 디버깅이 매우 어렵기 때문에 거의 의미가 없습니다.행에 발을 들여놓으면 프로그램의 상태나 의도를 알 수 없습니다.프로그램의 상태나 의도를 알 수 없습니다.프로그램의 의미를 파악하기 위해서는 (스텝 필터에 의해 많은 스택 프레임이 깊은 코드로 들어가지만) 단순히 if/else/call trivi를 걷는 것이 아니라 추가한 코드/lambda에서 정지할 수 있도록 많은 브레이크 포인트를 추가해야 합니다.모든 라인

기능적인 프로그래밍을 원하신다면 자바 이외의 것을 선택하시고 디버깅을 위한 툴이 준비되어 있기를 바랍니다.

1 - 메서드가 null을 반환할 수 있는 경우 공용 메서드 반환 유형으로:

여기 use case #1의 유용성을 보여주는 좋은 기사가 있습니다.여기 이 코드가 있습니다.

...
if (user != null) {
    Address address = user.getAddress();
    if (address != null) {
        Country country = address.getCountry();
        if (country != null) {
            String isocode = country.getIsocode();
            isocode = isocode.toUpperCase();
        }
    }
}
...

다음과 같이 변환됩니다.

String result = Optional.ofNullable(user)
  .flatMap(User::getAddress)
  .flatMap(Address::getCountry)
  .map(Country::getIsocode)
  .orElse("default");

getter 메서드의 반환값으로 Optional을 사용합니다.

여기...의 재미있는 용법이 있다.테스트

나는 내 프로젝트 중 하나를 심각하게 시험할 작정이고, 따라서 나는 주장을 펼친다. 단지 내가 검증해야 할 것과 그렇지 않은 것만이 있을 뿐이다.

그래서 나는 다음과 같이 주장하기 위한 것들을 만들고 그것들을 검증하기 위해 주장하기 위한 것들을 사용한다.

public final class NodeDescriptor<V>
{
    private final Optional<String> label;
    private final List<NodeDescriptor<V>> children;

    private NodeDescriptor(final Builder<V> builder)
    {
        label = Optional.fromNullable(builder.label);
        final ImmutableList.Builder<NodeDescriptor<V>> listBuilder
            = ImmutableList.builder();
        for (final Builder<V> element: builder.children)
            listBuilder.add(element.build());
        children = listBuilder.build();
    }

    public static <E> Builder<E> newBuilder()
    {
        return new Builder<E>();
    }

    public void verify(@Nonnull final Node<V> node)
    {
        final NodeAssert<V> nodeAssert = new NodeAssert<V>(node);
        nodeAssert.hasLabel(label);
    }

    public static final class Builder<V>
    {
        private String label;
        private final List<Builder<V>> children = Lists.newArrayList();

        private Builder()
        {
        }

        public Builder<V> withLabel(@Nonnull final String label)
        {
            this.label = Preconditions.checkNotNull(label);
            return this;
        }

        public Builder<V> withChildNode(@Nonnull final Builder<V> child)
        {
            Preconditions.checkNotNull(child);
            children.add(child);
            return this;
        }

        public NodeDescriptor<V> build()
        {
            return new NodeDescriptor<V>(this);
        }
    }
}

NodeAssert 클래스에서는 다음 작업을 수행합니다.

public final class NodeAssert<V>
    extends AbstractAssert<NodeAssert<V>, Node<V>>
{
    NodeAssert(final Node<V> actual)
    {
        super(Preconditions.checkNotNull(actual), NodeAssert.class);
    }

    private NodeAssert<V> hasLabel(final String label)
    {
        final String thisLabel = actual.getLabel();
        assertThat(thisLabel).overridingErrorMessage(
            "node's label is null! I didn't expect it to be"
        ).isNotNull();
        assertThat(thisLabel).overridingErrorMessage(
            "node's label is not what was expected!\n"
            + "Expected: '%s'\nActual  : '%s'\n", label, thisLabel
        ).isEqualTo(label);
        return this;
    }

    NodeAssert<V> hasLabel(@Nonnull final Optional<String> label)
    {
        return label.isPresent() ? hasLabel(label.get()) : this;
    }
}

즉, 라벨을 확인하고 싶을 때만 어설션이 트리거된다는 뜻입니다!

Optional이 잠재적으로 null 값을 반환하는 메서드를 대체한다고 생각하지 않습니다.

기본 개념은 다음과 같습니다.값이 없다고 해서 미래에 사용할 수 있는 것은 아닙니다.findById(-1)와 findById(67)의 차이입니다.

발신자에 대한 옵션의 주요 정보는 지정된 값을 신뢰하지 않을 수 있지만 언젠가 사용할 수 있을 수 있다는 것입니다.어쩌면 다시 없어지고 나중에 다시 돌아올지도 몰라.온/오프 스위치 같은 거죠.조명을 켜거나 끌 수 있는 "옵션"이 있습니다.하지만 당신이 켤 수 있는 불이 없다면 당신은 선택의 여지가 없다.

따라서 이전에 null이 반환되었을 가능성이 있는 모든 곳에 Optionals를 도입하는 것은 너무 복잡하다고 생각합니다.null은 계속 사용하지만 트리 루트, 느린 초기화 및 명시적인 검색 방법 등 제한된 영역에서만 사용합니다.

Optionalclass를 사용하면null보다 나은 대안을 제시합니다.

  • 이를 통해 개발자는 미검출을 방지하기 위해 존재 여부를 확인할 수 있습니다.NullPointerException

  • API는 없을 수 있는 값을 어디서 볼 수 있는지 알 수 있기 때문에 문서화가 더 잘 됩니다.

Optional는 오브젝트: ; ; ; ; ; ; ; ; ; ; ; ; 에 대한 추가 작업을 위한 편리한 API를 제공합니다.

또한 많은 프레임워크가 이 데이터 유형을 적극적으로 사용하고 API에서 데이터를 반환합니다.

의 의미론은 변경 불가능한 반복기 설계 패턴 인스턴스와 유사합니다.

  • 오브젝트를 참조할 수도 있고 참조하지 않을 수도 있습니다( 참조).
  • 오브젝트를 참조하고 있는 경우는 (를 사용하여) 참조할 수 있습니다.
  • 그러나 시퀀스의 다음 위치로 진행할 수 없습니다(그것은next()메서드).

따라서 반환 또는 전달을 고려하십시오.OptionalJava 를 사용하는 것을 검토했을 가능성이 있는 콘텍스트에서 참조할 수 있습니다.

보이다Optional옵션 타입 T가 다음과 같은 원시 타입인 경우에만 도움이 됩니다.int,long,char, 등. "진짜" 수업의 경우, 당신이 사용할 수 있기 때문에 나는 이해할 수 없다.null어쨌든 가치.

여기서 (또는 다른 유사한 언어 개념에서) 가져온 것 같습니다.

Nullable<T>

C#에서는 이것은Nullable<T>는 값 유형을 랩하기 위해 오래 전에 도입되었습니다.

다음은 의 인스턴스에서 수행할 수 있는 몇 가지 방법입니다.Optional<T>:

  • map
  • flatMap
  • orElse
  • orElseThrow
  • ifPresentOrElse
  • get

다음은 에 대해 수행할 수 있는 모든 방법입니다.null:

  • (없음)

이것은 정말로 사과와 오렌지의 비교입니다.Optional<T>는 객체의 실제 인스턴스입니다(단,null…하지만 그것은 아마 버그가 될 것이다)null는 중단된 객체입니다.할 수 있는 모든 것밖에 없어null그것이 사실인지 아닌지를 확인하는 것이다.null,그렇지 않으면.오브젝트에 메서드를 사용하고 싶다면Optional<T>특별한 리터럴을 원하신다면null널 위한 거야

null구성되지 않습니다.단순히 분기할 수 있는 값만 구성할 수는 없습니다.그렇지만Optional<T>작곡은 합니다.

예를 들어, 다음을 사용하여 "비지 않은 경우 이 함수 적용"의 임의의 긴 체인을 만들 수 있습니다.map또는 명령어 블록을 효과적으로 만들 수 있습니다.이 블록은 비어 있지 않은 경우에 옵션으로 사용할 수 있습니다.ifPresent또는 를 사용하여 "if/else"를 만들 수 있습니다.ifPresentOrElse비어 있지 않은 경우 또는 다른 코드를 실행하는 경우 비어 있지 않은 옵션을 사용합니다.

이 시점에서 언어의 진정한 제한에 직면하게 됩니다.매우 중요한 코드의 경우, 그것들을 람다에 싸서 메서드에 건네야 합니다.

    opt.ifPresentOrElse(
            string -> { // if present...
                // ...
            }, () -> { // or else...
                // ...
            }
    );

스타일리시하게 보면, 어떤 사람들에게는 충분하지 않을 수도 있어요.

이음새 없이 할 수 있다Optional<T>는 패턴 매칭할 수 있는 대수 데이터 타입입니다(이것은 명백히 의사 코드입니다).

    match (opt) {
        Present(str) => {
            // ...
        }
        Empty =>{
            // ...
        }
    }

어쨌든, 요약하자면:Optional<T>는 매우 견고한 비어 있거나 존재하는 개체입니다. null그냥 센티넬 값일부탁드립니다

주관적으로 무시된 이유

효율이 사용 여부를 결정해야 한다고 효과적으로 주장하는 몇몇 사람들이 있는 것 같다.Optional<T>또는 브런치로nullsentinel 값이는 일반적인 경우에서 원형이 아닌 언제 객체를 만들어야 하는지에 대한 규칙을 만드는 것과 비슷합니다.이미 사물을 좌우, 위에서 아래로 항상 만드는 것이 관용적인 언어로 작업하고 있는데 그것을 토론의 출발점으로 삼는 것은 좀 우스꽝스럽다고 생각한다.

Java SE 8은 java.util이라는 새로운 클래스를 도입했습니다.선택적.

빈 Optional 또는 Optional 값을 null로 만들 수 있습니다.

Optional<String> emptyOptional = Optional.empty(); 

값이 null이 아닌 [Optional]는 다음과 같습니다.

String valueString = new String("TEST");
Optional<String> optinalValueString = Optional.of(valueString );

값이 있는 경우 작업

Optional 객체가 생성되었으므로 값의 유무를 명시적으로 처리하는 데 사용할 수 있는 메서드에 액세스할 수 있습니다.다음과 같이 늘체크를 잊지 않고 실행할 필요가 없습니다.

String nullString = null;
if (nullString != null) {
    System.out.println(nullString);
}

ifPresent() 메서드는 다음과 같이 사용할 수 있습니다.

Optional<String> optinalString= null;
optinalString.ifPresent(System.out::println);

package optinalTest;

import java.util.Optional;

public class OptionalTest {
    public Optional<String> getOptionalNullString() {
        return null;
//      return Optional.of("TESt");
    }

    public static void main(String[] args) {

        OptionalTest optionalTest = new OptionalTest();

        Optional<Optional<String>> optionalNullString = Optional.ofNullable(optionalTest.getOptionalNullString());

        if (optionalNullString.isPresent()) {
            System.out.println(optionalNullString.get());
        }
    }
}

언급URL : https://stackoverflow.com/questions/23454952/uses-for-optional

반응형