선택적인 용도
6 개월 이상 동안 Java 8을 사용해 왔으므로 새로운 API 변경에 매우 만족합니다. 내가 아직도 확신하지 못하는 영역은 언제 사용해야하는지 Optional
입니다. 나는 어디에서나 사용할 수있는 곳 어디에서나 사용하고 싶어하는 것 같습니다 null
.
그것을 사용할 수있는 상황이 많이있는 것 같으며 이점 (가독성 / null 안전성)을 추가하거나 추가 오버 헤드를 유발하는지 확실하지 않습니다.
그래서 몇 가지 예가 있으며, Optional
유익한 지에 대한 커뮤니티의 생각에 관심 이 있습니다.
1 - 공공 방법의 반환 형식으로 방법은 반환 할 때 null
:
public Optional<Foo> findFoo(String id);
2-param이 다음 null
과 같은 경우 메소드 매개 변수로 :
public Foo doSomething(String id, Optional<Bar> barOptional);
3-Bean의 선택적 멤버로서 :
public class Book {
private List<Pages> pages;
private Optional<Index> index;
}
4-안으로 Collections
:
일반적으로 나는 생각하지 않습니다 :
List<Optional<Foo>>
값 등 filter()
을 제거 하는 데 사용할 수 있기 때문에 무엇이든 추가 null
하지만 Optional
컬렉션에 잘 사용 됩니까?
내가 놓친 사건이 있습니까?
요점은 Optional
반환 값이 없음을 나타내는 값을 반환하는 함수를위한 수단을 제공하는 것입니다. 이 토론을 참조하십시오 . 이를 통해 호출자는 일련의 유창한 메소드 호출을 계속할 수 있습니다.
이것은 OP 질문에서 유스 케이스 1 과 가장 일치합니다 . 비록 값의 부재는 보다 더 정확한 배합이다 널 (null) 과 같은 이후 IntStream.findFirst
는 null을 반환하지 않을 수는.
유스 케이스 # 2의 경우 , 선택적 인수를 메소드에 전달하면 이것이 작동하도록 만들 수 있지만 다소 어색합니다. 문자열 다음에 선택적 두 번째 문자열을 취하는 메소드가 있다고 가정하십시오. Optional
두 번째 인수로 a를 허용하면 다음 과 같은 코드가 생성됩니다.
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
반대 하지만, 나는 여전히 그들의 타당성을 확신합니다 (분명히).
어디에서나 옵션 사용
일반적으로
사용에 대해Optional
전체 블로그 게시물을 작성 했지만 기본적으로 다음과 같습니다.
- 가능한 한 선택을 피하기 위해 수업을 디자인
- 나머지 모든 경우에 기본값은
Optional
대신 사용하는 것이 좋습니다null
- 다음에 대한 예외를 만들 수 있습니다
- 지역 변수
- 개인 메소드에 값과 인수를 리턴
- 성능이 중요한 코드 블록 (예상치 않고 프로파일 러 사용)
처음 두 예외는에서 래핑 및 래핑 해제 참조의 인식 된 오버 헤드를 줄일 수 있습니다 Optional
. 그들은 null이 법적으로 한 인스턴스에서 다른 인스턴스로 경계를 넘길 수 없도록 선택됩니다.
이것은 거의 Optional
s만큼 나쁜 컬렉션에서 s를 거의 허용하지 않습니다 null
. 하지 마십시오. ;)
당신의 질문에 대하여
- 예.
- 과부하가 옵션이 아닌 경우 가능합니다.
- 다른 접근 방식 (하위 분류, 꾸미기 등)이 선택 사항이 아닌 경우 가능합니다.
- 안돼!
장점
이렇게하면 null
코드 기반에서 s 의 존재가 줄어 듭니다 . 그러나 그것은 요점조차 아닙니다. 다른 중요한 장점이 있습니다.
의도를 명확하게한다
사용 Optional
하면 변수가 선택 사항임을 명확하게 나타냅니다. 코드를 읽거나 API를 사용하는 소비자는 아무것도 없을 수 있으며 값에 액세스하기 전에 확인이 필요하다는 사실로 인해 당황 할 것입니다.
불확실성을 제거
없이 Optional
a의 의미를 null
발생 불분명하다. 상태를 합법적으로 표현 Map.get
하거나 (참조 ) 초기화 누락 또는 실패와 같은 구현 오류 일 수 있습니다.
이 지속적으로 사용함에 따라 크게 바뀝니다 Optional
. 여기서 이미 발생은 null
버그가 있음을 나타냅니다. (값을 잃어 Optional
버릴 수 있기 때문에를 사용했을 것입니다.) 이것은 이것의 의미에 대한 질문 null
이 이미 답변 되었기 때문에 널 포인터 예외 디버깅을 훨씬 쉽게 만듭니다 .
더 많은 Null 검사
이제는 null
더 이상 아무것도 할 수 없으므로 모든 곳에서 시행 할 수 있습니다. 주석, 어설 션 또는 일반 검사를 사용하여이 인수 또는 반환 유형이 null 일 수 있는지 여부를 생각할 필요가 없습니다. 할 수 없습니다!
단점
물론, 총알은 없습니다 ...
공연
추가 인스턴스에 값 (특히 기본 요소)을 랩핑하면 성능이 저하 될 수 있습니다. 꽉 조이는 루프에서는 눈에 띄거나 더 나빠질 수 있습니다.
컴파일러는 수명이 짧은 수명 동안 추가 참조를 우회 할 수 있습니다 Optional
. Java 10에서 값 유형 은 추가로 패널티를 줄이거 나 제거 할 수 있습니다.
직렬화
Optional
직렬화 할 수 없지만 해결 방법 이 지나치게 복잡하지 않습니다.
불변
Java에서 제네릭 형식의 불일치로 인해 실제 값 형식이 제네릭 형식 인수로 푸시되면 특정 작업이 번거로워집니다. 여기에 예가 있습니다 ( "파라 메트릭 다형성"참조) .
개인적으로 필자는 IntelliJ의 코드 검사 도구 를 사용 @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에서 작동하며 값을 줄 바꿈하거나 줄 바꿈 할 필요가 없습니다. (또는 랩퍼 오브젝트 작성)
구아바 옵션과 위키 페이지에 잘 나와 있다고 생각합니다.
널 (null)에 이름을 부여함으로써 가독성이 향상되는 것 외에, Optional의 가장 큰 장점은 바보 방지입니다. 선택 사항을 적극적으로 풀고 해당 사례를 해결해야하기 때문에 프로그램을 전혀 컴파일하지 않으려면 결석 사례에 대해 적극적으로 생각해야합니다. 널 (Null)은 단순히 물건을 잊어 버릴 수있게 해주 며, FindBugs가 도움이되지만 문제를 거의 해결하지 못한다고 생각합니다.
이것은 "존재할 수도 있고 없을 수도있는"값을 반환 할 때 특히 관련이 있습니다. other.method (a, b)가 other.method를 구현할 때 a가 null 일 수 있다는 것을 잊어 버릴 것보다 other.method (a, b)가 null 값을 반환 할 수 있다는 것을 잊어 버릴 가능성이 훨씬 높습니다. Optional을 반환하면 호출자가 코드를 컴파일하기 위해 객체 자체를 언랩해야하므로이 경우를 잊을 수 없습니다. -(출처 : Guava Wiki-null 사용 및 피하기-요점은 무엇입니까? )
Optional
약간의 오버 헤드가 추가되지만 객체의 부재를 명시 하고 프로그래머가 상황을 처리하도록 강요하는 것이 확실한 이점이라고 생각 합니다. 누군가가 사랑하는 != null
수표를 잊어 버리는 것을 방지합니다 .
2 의 예를 들어 작성하면 훨씬 더 명확한 코드라고 생각합니다.
if(soundcard.isPresent()){
System.out.println(soundcard.get());
}
...보다
if(soundcard != null){
System.out.println(soundcard);
}
저 Optional
에게는 사운드 카드가 없다는 사실을 더 잘 포착합니다.
당신의 요점에 대한 나의 2 ¢ :
public Optional<Foo> findFoo(String id);
-확실하지 않습니다. 어쩌면 나는 비어 있거나를 포함Result<Foo>
할 수 있는를 반환 할 것Foo
입니다. 비슷한 개념이지만 실제로는 아닙니다Optional
.public Foo doSomething(String id, Optional<Bar> barOptional);
-Peter Lawrey의 답변 에서와 같이 @Nullable 및 findbugs check를 선호합니다 . 이 토론 도 참조하십시오 .- 귀하의 도서 예-선택 사항을 내부적으로 사용할 것인지 확실하지 않습니다. 복잡성에 따라 달라질 수 있습니다. 책의 "API"의 경우 책을 사용하여
Optional<Index> getIndex()
해당 책에 색인이 없을 수 있음을 명시 적으로 나타냅니다. - 컬렉션에서 사용하지 않고 컬렉션에서 null 값을 허용하지 않습니다.
일반적으로 null
s의 통과를 최소화하려고합니다 . (한 번 태워 ...) 나는 적절한 추상화를 찾아서 동료 프로그래머에게 특정 반환 값이 실제로 나타내는 것을 나타낼 가치가 있다고 생각합니다.
에서 오라클 튜토리얼 :
Optional의 목적은 코드베이스의 모든 단일 null 참조를 대체하는 것이 아니라 메서드의 서명을 읽음으로써 선택적 값을 기대할 수 있는지를 알려주는 더 나은 API를 디자인하는 데 도움이되는 것입니다. 또한 Optional은 값의 부재를 처리하기 위해 Optional을 적극적으로 래핑 해제하도록합니다. 결과적으로 의도하지 않은 널 포인터 예외로부터 코드를 보호합니다.
1-메소드가 널을 리턴 할 수있는 공용 메소드 리턴 유형
여기입니다 좋은 기사 쇼 유스 케이스 # 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 메소드 의 리턴 값으로 사용 합니다.
다음은 흥미로운 사용법입니다.
내 프로젝트 중 하나를 심하게 테스트하려고하므로 어설 션을 작성합니다. 내가 확인해야 할 것이 있고 내가 확인하지 않은 것이 있습니다.
따라서 다음과 같이 어설 션 할 내용을 작성하고 어설 션을 사용하여 확인합니다.
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;
}
}
즉, 레이블을 확인하려는 경우 어설 션이 실제로 트리거됩니다.
선택 사항이 잠재적으로 null 값을 반환하는 메서드를 대체하는 것으로 생각하지 않습니다.
기본 아이디어는 다음과 같습니다. 값이 없다고해서 미래에 사용할 수있는 것은 아닙니다. findById (-1)와 findById (67)의 차이점입니다.
발신자에 대한 옵션의 주요 정보는 주어진 값을 신뢰할 수 없지만 때로는 사용할 수 있다는 것입니다. 어쩌면 다시 사라지고 나중에 다시 올 수 있습니다. 온 / 오프 스위치와 같습니다. 조명을 켜거나 끄는 "옵션"이 있습니다. 그러나 전원을 켤 수있는 조명이 없으면 옵션이 없습니다.
따라서 이전에 null이 반환 될 수있는 모든 곳에서 Optionals를 소개하는 것은 너무 지저분합니다. 나는 여전히 null을 사용하지만 트리의 루트, 게으른 초기화 및 명시적인 find-methods와 같은 제한된 영역에서만 사용합니다.
Optional
class를 사용하면 사용을 피하고 null
더 나은 대안을 제공 할 수 있습니다 .
이를 통해 개발자는 잡히지 않도록 존재 여부를 확인하도록 권장합니다
NullPointerException
.누락 될 수있는 값을 예상 할 수있는 위치를 볼 수 있기 때문에 API가 더 잘 문서화됩니다.
Optional
객체에 대한 추가 작업을위한 편리한 API를 제공합니다 isPresent()
. get()
; orElse()
; orElseGet()
; orElseThrow()
; map()
; filter()
; flatmap()
.
또한 많은 프레임 워크가이 데이터 유형을 적극적으로 사용하여 API에서 반환합니다.
보인다는 Optional
옵션의 종류 (T)가 같은 원시적 형태 인 경우에만 유용합니다 int
, long
, char
, 등 "진짜"클래스의 경우, 그것은 당신이 사용할 수있는 나에게 이해가되지 않습니다 null
어쨌든 값입니다.
나는 그것이 여기 (또는 다른 유사한 언어 개념)에서 가져온 것으로 생각합니다.
C #에서는 Nullable<T>
값 형식을 래핑하기 위해 오래 전에 소개되었습니다.
는 반복자 디자인 패턴의 변경 불가능한 경우와 유사한 의미를 가지고 :Optional
- 그것은 수도 있고 (에 의해 주어진 객체를 참조하지 않을 수 있습니다
isPresent()
) get()
객체를 참조하는 경우 참조를 사용하여 참조 해제 할 수 있습니다- 그러나 시퀀스의 다음 위치로 진행할 수는 없습니다 (
next()
방법 이 없습니다 ).
따라서 Optional
이전에 Java 사용을 고려했을 수있는 컨텍스트에서 리턴 또는 전달 을 고려하십시오 Iterator
.
자바에서는 함수형 프로그래밍에 중독되지 않는 한 사용하지 마십시오.
그들은 메소드 인수로 자리를 차지하지 않습니다 (언젠가 누군가가 비어있는 옵션이 아니라 null 옵션을 전달할 것이라고 약속합니다).
그들은 반환 값에 대해서는 의미가 있지만 행동 클래스를 확장하기 위해 클라이언트 클래스를 초대합니다.
FP와 체인은 단순히 읽기가 아니라 디버깅하기가 매우 어렵 기 때문에 java와 같은 명령형 언어에서 거의 자리를 차지하지 않습니다. 줄을 밟으면 프로그램의 상태 나 의도를 알 수 없습니다. 단계 필터에도 불구하고 종종 자신과 많은 스택 프레임이 아닌 코드로 깊이 파악해야하며 추가 한 코드 / 람다에서 중지 할 수 있도록 많은 중단 점을 추가해야합니다. 단순히 if / else / call 사소한 라인을 걷는 대신.
함수형 프로그래밍을 원한다면 java 이외의 것을 선택하고 디버깅 도구가 있기를 바랍니다.
Java SE 8에는 java.util이라는 새로운 클래스가 도입되었습니다.
널 (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
'Programing' 카테고리의 다른 글
다른 JS 파일에 JS 파일을 포함시키는 방법은 무엇입니까? (0) | 2020.04.14 |
---|---|
홈브류, 맥 포트 또는 기타 패키지 설치 도구의 차이점 / 사용은 무엇입니까? (0) | 2020.04.14 |
Java에 String.Empty가없는 이유는 무엇입니까? (0) | 2020.04.14 |
HTML 속성 내에서 따옴표를 올바르게 이스케이프 처리하려면 어떻게해야합니까? (0) | 2020.04.14 |
백그라운드 작업, 진행률 대화 상자, 방향 변경-100 % 작동하는 솔루션이 있습니까? (0) | 2020.04.14 |