변수를 null 검사하는 것보다 선택적 우선 순위를 사용하는 이유는 무엇입니까?


25

두 가지 코드 예제를 보자.

if(optional.isPresent()) {
    //do your thing
}

if(variable != null) {
    //do your thing
}

가장 분명한 차이점을 알 수있는 한, Optional은 추가 개체를 만들어야한다는 것입니다.

그러나 많은 사람들이 옵션을 빠르게 채택하기 시작했습니다. 널 (null) 검사와 비교하여 옵션을 사용하면 어떤 이점이 있습니까?


4
isPresent를 거의 사용하지 않으려면 ifPresent 또는 map
jk

6
@jk. 지난 10 년 동안 if성명서가 너무 많기 때문에 모두 모나드 추상화와 람다를 사용하고 있기 때문 입니다.
user253751

2
@immibis 나는 다른 사용자와이 주제에 대해 오랜 논쟁을 벌였다. 요점은 if(x.isPresent) fails_on_null(x.get)타입 시스템을 빠져 나가서 조건과 함수 호출 사이의 (거리가 짧은) 거리에서 코드가 "머리에서"깨지지 않도록 보장해야한다는 것입니다. 에서 optional.ifPresent(fails_on_null)타입 시스템 당신이 보증을 만들고, 당신은 걱정할 필요가 없습니다.
ziggystar

1
Java Optional.ifPresent(및 다양한 다른 Java 구문) 를 사용하는 Java의 주요 결함은 최종 변수 만 효과적으로 수정할 수 있으며 확인 된 예외를 throw 할 수 없다는 것입니다. ifPresent불행히도 종종 피할 수있는 충분한 이유 입니다.
Mike

답변:


19

Optional당신의 머리에서 모든 것을해야 할 일을하기 위해 타입 시스템을 활용합니다 : 주어진 참조가되는지 아닌지를 기억합니다 null. 이거 좋다 컴파일러가 지루한 약물 작업을 처리하고 창의적이고 흥미로운 작업에 대한 인간의 생각을 예약하는 것이 항상 현명합니다.

이 없으면 Optional코드의 모든 참조는 폭발하지 않은 폭탄과 같습니다. 그것에 접근하면 유용한 일을 할 수 있고, 그렇지 않으면 예외로 인해 프로그램이 종료 될 수 있습니다.

Optional 및 without null옵션을 사용하면 설정되지 않은 상태에서 일반 참조에 대한 모든 액세스가 성공하고이를 확인하지 않으면 Optional에 대한 모든 참조가 성공합니다. 그것은 유지 관리면에서 큰 승리입니다.

불행히도, 현재 제공되는 대부분의 언어는 Optional폐지되지 않았 null으므로 "절대적으로 아니오 null, 절대로" 라는 엄격한 정책을 세워야 만이 개념으로부터 이익을 얻을 수 있습니다 . 그러므로, Optional예를 들어 자바는 이상적으로 매력적이지 않다.


귀하의 답변이 최상위 답변이므로 람다의 사용법을 장점으로 추가하는 것이 좋습니다. 장래 에이 기사를 읽는 사람에게는 – 내 대답 참조)
William Dunne

대부분의 현대 언어는 Kotlin, Typescript, AFAIK와 같은 Null이 아닌 유형을 제공합니다.
Zen

5
IMO 이것은 @Nullable 주석으로 처리하는 것이 좋습니다. Optional값이 null
Hilikus

18

Optional다른 답변이 덮여대로, 실패 할 수 있습니다 운영에 대한 강한 타이핑을 제공하지만, 즉 지금까지 가장 흥미 롭거나 가치있는 일에서 Optionals테이블에 가져다. 장애 검사 지연 또는 방지 기능과 장애가 발생할 수있는 많은 작업을 쉽게 구성 할 수있는 기능이 훨씬 유용합니다.

optional예제 코드 의 변수 가 있다면 각각 실패 할 수있는 두 가지 추가 단계를 수행해야했습니다. 도중에 단계가 실패하면 대신 기본값을 리턴하려고합니다. Optionals올바르게 사용하면 다음과 같은 결과가 나타납니다.

return optional.flatMap(x -> x.anotherOptionalStep())
               .flatMap(x -> x.yetAnotherOptionalStep())
               .orElse(defaultValue);

null나는 세 번 확인했을 것이다 null코드의 복잡성 및 유지 보수 두통을 많이 추가하기 전에 진행. Optionals받는 사람 내장이 확인해야 flatMap하고 orElse기능을.

참고 isPresent한 번 호출하지 않았 으므로을 사용할 때 코드 냄새로 생각해야합니다 Optionals. 그렇다고 반드시 사용 해서는 안된다는 의미는 아니며 isPresent더 나은 방법이 있는지 확인하기 위해 코드를 철저히 조사해야합니다. 그렇지 않으면 옳습니다 null. 를 사용하는 것보다 한계 유형의 안전 혜택 만 얻습니다 .

또한 중간 결과에서 null 포인터로부터 코드의 다른 부분을 보호하기 위해이 모든 것을 하나의 함수로 캡슐화하는 것에 대해 걱정하지 않습니다. .orElse(defaultValue)예를 들어 다른 기능을 사용하는 것이 더 합리적 이라면 거기에 넣는 것에 대한 요구 사항이 훨씬 적고 필요에 따라 다른 기능간에 작업을 작성하는 것이 훨씬 쉽습니다.


10

그것은 사람들이 종종 (올바르거나 잘못) 돌려주지 않을 것이라고 생각하는 유효한 응답으로서의 null 가능성을 강조합니다. null이 유효한 경우 몇 번 강조 표시하면 수많은 무의미한 null 검사로 코드를 낭비하지 않아도됩니다.

이상적으로 변수를 null로 설정하면 컴파일 시간 오류가 발생하지만 선택 사항입니다. 런타임 널 포인터 예외를 제거합니다. 분명히 하위 호환성은 슬프게도 이것을 배제합니다.


4

예를 들어 보겠습니다.

class UserRepository {
     User findById(long id);
}

이 방법이 의도 한 것이 확실합니다. 그러나 저장소에 지정된 ID를 가진 사용자가 없으면 어떻게됩니까? 예외가 발생하거나 null을 반환합니까?

두 번째 예 :

class UserRepository {
     Optional<User> findById(long id);
}

이제 주어진 아이디를 가진 사용자가 없으면 어떻게됩니까? 맞습니다. Optional.absent () 인스턴스가 생기고 Optional.isPresent ()로 확인할 수 있습니다. Optional을 사용한 메소드 서명은 계약에 대해보다 명확합니다. 방법이 어떻게 동작해야하는지 즉시 알 수 있습니다.

또한 클라이언트 코드를 읽을 때 이점이 있습니다.

User user = userRepository.findById(userId).get();

나는 즉각적인 코드 냄새로 .get ()을 보도록 눈을 훈련시켰다. 클라이언트가 호출 된 메소드의 계약을 의도적으로 무시한다는 의미입니다. Optional이없는 ​​것보다 이것을 보는 것이 훨씬 쉽습니다.이 경우 호출 된 메소드의 계약이 무엇인지 (즉, null 허용 여부에 관계없이) 즉시 알지 못하므로 먼저 확인해야하기 때문입니다.

Optional은 반환 유형 Optional이있는 메소드는 null을 반환하지 않는 규칙과 함께 사용되며 일반적으로 Optional return type이없는 메소드는 null을 반환하지 않는 (강한) 규칙을 사용합니다 (하지만 @Nonnull, @NotNull 또는 이와 유사한 방식으로 주석을 추가하는 것이 좋습니다). .


3

Optional<T>사용하면 메소드에 대한 유효한 응답 / 반환 값으로 "실패"또는 "결과 없음"을 가질 수 있습니다 (예 : 데이터베이스 조회). 실패 / 결과 없음을 나타내는 Optional대신 사용을 사용하면 null몇 가지 장점이 있습니다.

  • 그것은 "실패" 옵션 이라는 것을 분명히 전달합니다 . 메소드의 사용자는 null리턴 될지 여부를 추측 할 필요가 없습니다 .
  • 값은 null, 내 의견으로는 적어도해야 하지 의미가 완전히 명확하지 않을 수 있습니다으로 아무것도 표시하는 데 사용 될 수있다. 가비지 콜렉터에게 이전에 참조 된 오브젝트가 수집 될 수 있음을 알리는 데 사용해야합니다.
  • Optional클래스는 조건부로 값을 처리 ifPresent()하거나 (예 :) 투명한 방법으로 기본값을 정의 하는 많은 멋진 메소드를 제공합니다 ( orElse()).

불행히도 객체 자체가 여전히 그렇듯이 null코드 검사 가 필요하지 않습니다 .Optionalnull


4
이것은 실제로 Optional이 아닙니다. 오류를보고하려면 예외를 사용하십시오. 당신이 할 수없는 경우가 포함 된 유형 사용 결과 또는 오류 코드를 .
James Youngman

나는 매우 동의하지 않습니다. Optional.empty ()는 내 의견으로는 실패 또는 존재하지 않음을 보여주는 좋은 방법입니다.
LegendLength

@LegendLength, 나는 실패의 경우 강력히 동의하지 않아야합니다. 함수가 실패하면 그냥 빈 것이 아니라 "나는 실패했다"고 설명하는 것이 좋습니다.
Winston Ewert

죄송합니다. 검색하는 동안 이름이 'x'인 직원을 찾지 못하는 것처럼 '예상 실패'를 의미합니다.
LegendLength

3

다른 답변 외에도 깨끗한 코드를 작성할 때 Optionals의 다른 주요 이점은 아래와 같이 값이 존재하는 경우 Lambda 표현식을 사용할 수 있다는 것입니다.

opTr.ifPresent(tr -> transactions.put(tr.getTxid(), tr));

2

다음 방법을 고려하십시오.

void dance(Person partner)

이제 몇 가지 호출 코드를 보자 :

dance(null);

이것은 dance널을 예상하지 않았기 때문에 충돌을 추적하기 어려울 수 있습니다.

dance(optionalPerson)

춤이 Person아니라고 기대했기 때문에 컴파일 오류가 발생 합니다.Optional<Person>

dance(optionalPerson.get())

내가 사람이 없다면, 이것은 불법적 Optional<Person>으로 사람 으로 전환하려고 시도한 시점 에서이 줄에 예외가 발생합니다 . 열쇠는 null을 전달하는 것과 달리 프로그램의 다른 위치가 아닌 여기에 추적을 제외하고는 것입니다.

선택적으로 잘못 사용하면 문제점을 쉽게 추적 할 수 있고, 널을 잘못 사용하면 문제점을 추적하기가 어렵습니다.


1
Optional.get()코드를 호출 할 때 예외가 발생하는 경우 Optional.isPresent()(OP에 표시된대로) 먼저 확인하지 않고 Optional.get을 호출하지 않아야 optionalPersion.ifPresent(myObj::dance)합니다. 그렇지 않으면 작성할 수 있습니다.
Chris Cooper

@QmunkE, 그렇습니다. 옵션이 비어 있지 않다는 것을 이미 알고 있다면 (isPresent를 호출했거나 알고리즘이이를 보장하기 때문에) Optional.get () 만 호출해야합니다. 그러나 나는 맹목적으로 isPresent를 확인한 다음 결석 값을 무시하여 많은 실패를 초래하는 침묵의 실패를 생성하는 것에 대해 걱정하고 있습니다.
Winston Ewert

1
나는 옵션을 좋아한다. 그러나 평범한 오래된 널 포인터는 실제 코드에서 거의 문제가되지 않는다고 말할 것입니다. 거의 항상 문제의 코드 줄 근처에서 실패합니다. 그리고 저는이 주제에 관해 이야기 할 때 사람들에 의해 과장된 것 같습니다.
LegendLength

@LegendLength, 내 경험은 95 %의 사례가 실제로 NULL이 어디에서 왔는지 식별하기 위해 쉽게 추적 할 수 있다는 것입니다. 그러나 나머지 5 %는 추적하기가 매우 어렵습니다.
Winston Ewert

-1

Objective-C에서 모든 객체 참조는 선택 사항입니다. 이 때문에 게시 한 코드는 바보입니다.

if (variable != nil) {
    [variable doThing];
}

위와 같은 코드는 Objective-C에서 들어 본 적이 없습니다. 대신 프로그래머는 다음을 수행합니다.

[variable doThing];

variable값 이 포함되어 있으면 해당 값 doThing이 호출됩니다. 그렇지 않으면 해를 끼치 지 않습니다. 프로그램은이를 no-op로 취급하고 계속 실행합니다.

이것이 옵션의 진정한 이점입니다. 로 코드를 정리할 필요가 없습니다 if (obj != nil).


그것은 단지 조용히 실패하는 형태가 아닙니까? 경우에 따라 값이 null인지 확인하고 그것에 대해 무언가를 원할 수 있습니다.
LegendLength

-3

if (optional.isPresent ()) {

여기에 명백한 문제는 "선택"정말 경우이다 되고 없는 (즉,가 null) 다음 코드는 널 객체 참조에 대한 메서드를 호출하려고 NullReferenceException이 (또는 유사한)와 함께 날려 버릴 것입니다!

주어진 객체 유형의 null을 결정하는 정적 헬퍼 클래스 메소드를 작성하려고 할 수 있습니다.

function isNull( object o ) 
{
   return ( null == o ); 
}

if ( isNull( optional ) ) ... 

또는 아마도 더 유용합니다.

function isNotNull( object o ) 
{
   return ( null != o ); 
}

if ( isNotNull( optional ) ) ... 

그러나 이것들 중 어느 것이 실제로 원본보다 더 읽기 쉽고 이해 가능합니까?

if ( null == optional ) ... 
if ( null != optional ) ... 
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.