검색 메서드가 'null'을 반환해야 할까요? 아니면 반환 값을 생성할 수 없을 때 예외를 발생시켜야 할까요?[닫은]

StackOverflow https://stackoverflow.com/questions/175532

  •  05-07-2019
  •  | 
  •  

문제

개체가 발견되면 개체를 반환하는 메서드가 있습니다.

찾을 수 없는 경우 다음을 수행해야 합니다.

  1. null을 반환
  2. 예외를 던진다
  3. 다른
도움이 되었습니까?

해결책

항상 값을 찾을 것으로 기대하고 있다면 값이 누락 된 경우 예외를 던지십시오. 예외는 문제가 있음을 의미합니다.

값이 누락되거나 존재하고 둘 다 응용 프로그램 로직에 유효한 경우 NULL을 반환하십시오.

더 중요한 : 코드에서 다른 장소는 무엇을합니까? 일관성이 중요합니다.

다른 팁

진정으로 오류 인 경우에만 예외 만 던지십시오. 객체가 존재하지 않을 것으로 예상되면 널을 반환하십시오.

그렇지 않으면 선호의 문제입니다.

일반적으로 방법이 항상 객체를 반환 해야하는 경우 예외로 이동하십시오. 때때로 널을 예상하고 특정 방식으로 처리하려면 널과 함께 가십시오.

당신이 무엇을하든, 나는 "wtf"라는 문자열을 반환하는 세 번째 옵션에 대해 권고합니다.

NULL이 오류를 표시하지 않으면 NULL을 반환하십시오.

NULL이 항상 오류 인 경우 예외를 던지십시오.

NULL이 때때로 예외이라면 두 루틴을 코딩하십시오. 한 루틴은 예외를 던지고 다른 하나는 출력 매개 변수에서 객체를 반환하는 부울 테스트 루틴이며 객체를 찾을 수없는 경우 루틴이 거짓을 반환합니다.

시도 루틴을 오용하기는 어렵습니다. Null을 확인하는 것을 잊기 쉽습니다.

따라서 NULL이 오류 일 때 그냥 씁니다

object o = FindObject();

널이 오류가되지 않으면

if (TryFindObject(out object o)
  // Do something with o
else
  // o was not found

나는 방금 앞에서 언급 한 옵션을 다시 설정하고 새로운 옵션을 다음과 같이 던지고 싶었습니다.

  1. 널 리턴
  2. 예외를 던져
  3. 널 객체 패턴을 사용하십시오
  4. 부울 매개 변수를 귀하에게 제공하므로 발신자가 예외를 던지기를 원한다면 선택할 수 있습니다.
  5. 추가 매개 변수를 제공하면 발신자가 값이 없으면 다시받는 값을 설정할 수 있습니다.

또는 다음 옵션을 결합 할 수 있습니다.

getter의 여러 가지 버전을 제공하여 발신자가 어떤 방법으로 갈지 결정할 수 있습니다. 대부분의 경우 첫 번째는 검색 알고리즘을 구현하고 다른 하나는 첫 번째를 감싸는 것입니다.

Object findObjectOrNull(String key);
Object findObjectOrThrow(String key) throws SomeException;
Object findObjectOrCreate(String key, SomeClass dataNeededToCreateNewObject);
Object findObjectOrDefault(String key, Object defaultReturnValue);

하나의 구현 만 제공하기로 선택하더라도 계약을 명확히하기 위해 명명 컨벤션을 사용하고 싶을 수도 있으며 다른 구현을 추가하기로 결정해야합니다.

과도하게 사용해서는 안되지만 다양한 오류 처리 규칙이있는 수백 가지 다른 응용 프로그램에서 사용할 수있는 도우미 클래스를 작성할 때 도움이 될 수 있습니다.

널 객체 패턴을 사용하거나 예외를 던지십시오.

사용중인 API와 일치하십시오.

"대상을 찾을 수없는 예외적 인 사례입니까?" 프로그램의 일반 과정에서 발생할 것으로 예상되는 경우 예외적 인 행동이 아니기 때문에 예외를 제기해서는 안됩니다.

짧은 버전 : 예외를 사용하여 프로그램의 정상적인 제어 흐름을 처리하지 않도록 뛰어난 동작을 처리합니다.

-알란.

언어와 코드가 홍보하는지에 따라 다릅니다.

lbyl은 값을 확인해야한다고 말합니다 (따라서 Null을 반환하십시오)
EAFP는 단지 작업을 시도하고 실패한 지 확인한다고 말합니다 (예외를 던지기)

위에서 동의하지만 예외/오류 조건에는 예외가 사용되어야하며 점검을 사용할 때는 널을 반환하는 것이 가장 좋습니다.


Python의 EAFP vs. LBYL :
http://mail.python.org/pipermail/python-list/2003-may/205182.html (웹 아카이브)

예외를 던지는 장점 :

  1. 호출 코드의 클리너 제어 흐름. NULL을 확인하면 Try/Catch가 기본적으로 처리하는 조건부 분기를 주입합니다. NULL을 확인하는 것은 확인하는 것이 무엇인지 표시하지 않습니다. 예상하는 오류를 찾고 있으므로 NULL을 확인하고 있습니까? ?
  2. "NULL"의 의미의 모호성을 제거합니다. NULL은 오류를 대표하거나 NULL입니까 값에 실제로 저장된 것은 무엇입니까? 결정을 내릴 수있는 한 가지만있을 때만 말하기 어렵습니다.
  3. 응용 프로그램에서 메소드 동작 간의 일관성 향상. 예외는 일반적으로 메소드 서명에 노출되므로 응용 프로그램 계정의 메소드가 어떤 가장자리 케이스와 응용 프로그램이 예측 가능한 방식으로 반응 할 수 있는지 이해할 수 있습니다.

예제에 대한 자세한 내용은 다음을 참조하십시오. http://metatations.com/2011/11/17/returning-null-vs-throwing-an-exception/

예외는 계약에 의한 설계와 관련이 있습니다.

객체의 인터페이스는 실제로 두 객체 간의 계약이므로 발신자는 계약을 충족해야합니다. 그렇지 않으면 수신자가 예외로 실패 할 수 있습니다. 두 가지 가능한 계약이 있습니다

1) 모든 입력 메소드가 유효합니다.이 경우 객체를 찾을 수없는 경우 NULL을 반환해야합니다.

2) 일부 입력 만 유효합니다. 즉, 찾은 객체가 발생합니다. 이 경우 발신자가 입력이 올바른지 확인할 수있는 두 번째 방법을 제공해야합니다. 예를 들어

is_present(key)
find(key) throws Exception

두 번째 계약의 두 가지 방법을 모두 제공하는 경우에만 예외를 던질 수 있습니다.

나는 단지 널을 반환하고 발신자에게 의존하여 적절하게 처리하는 것을 선호합니다. (더 나은 단어가 없음) 예외는 내가 절대적으로 '확실한'이 방법이 객체를 반환 할 것입니다. 이 경우 실패는 예외적이어야하며 던져야합니다.

객체를 찾을 수 없다는 의미에 따라 다릅니다.

정상적인 상황이라면 Null을 반환하십시오. 이것은 한 번에 일어날 수있는 일이며 발신자는 그것을 확인해야합니다.

오류 인 경우 예외를 던지면 발신자는 누락 된 오브젝트의 오류 조건으로 무엇을 해야하는지 결정해야합니다.

대부분의 사람들은 일반적으로 일이 발생했을 때 예외 만 사용하는 것이 일반적으로 고급 관행을 고려하지만 궁극적으로는 효과가 있습니다.

여기에 몇 가지 제안이 더 있습니다.

컬렉션을 반환하는 경우 null 반환을 피하고, 먼저 null 검사 없이 열거형을 더 쉽게 처리할 수 있도록 빈 컬렉션을 반환하세요.

여러 .NET API는 호출자에게 개체를 찾을 수 없는 경우 실제로 예외 상황인지 여부를 선택할 수 있는 ThrowOnError 매개 변수 패턴을 사용합니다.Type.GetType이 이에 대한 예입니다.BCL의 또 다른 일반적인 패턴은 부울이 반환되고 값이 출력 매개 변수를 통해 전달되는 TryGet 패턴입니다.

일부 상황에서는 기본값이거나 동작이 없는 버전일 수 있는 Null 개체 패턴을 고려할 수도 있습니다.핵심은 코드 베이스 전체에서 null 검사를 피하는 것입니다.자세한 내용은 여기를 참조하세요. http://geekswithblogs.net/deller/archive/2006/09/08/90656.aspx

일부 함수에서는 매개 변수를 추가합니다.

..., bool verify = true)

True Means Throw, False는 일부 오류 반환 값을 반환합니다. 이런 식 으로이 함수를 사용하는 사람은 두 옵션을 모두 가지고 있습니다. 오류 처리를 잊어 버린 사람들의 이익을 위해서는 기본값이 사실이어야합니다.

예외를 던지는 대신 널을 반환하고 API 문서에서 널 리턴 값의 가능성을 명확하게 문서화하십시오. 호출 코드가 API를 존중하지 않고 NULL 케이스를 확인하면 어쨌든 일종의 "NULL 포인터 예외"가 발생할 수 있습니다. :)

C ++에서는 객체를 찾는 방법을 설정하는 3 가지 맛을 생각할 수 있습니다.

옵션 a

Object *findObject(Key &key);

물체를 찾을 수 없을 때 null을 반환하십시오. 멋지고 간단합니다. 나는 이것과 함께 갈 것이다. 아래의 대안 적 접근법은 아웃 람을 싫어하는 사람들을위한 것입니다.

옵션 b

void findObject(Key &key, Object &found);

객체를 수신 할 변수를 참조하십시오. 객체를 찾을 수 없을 때이 방법은 예외를 던졌습니다. 이 협약은 물체가 발견되지 않을 것으로 예상되지 않으면 더 적합 할 것입니다. 따라서 예상치 못한 사례임을 나타 내기 위해 예외를 던집니다.

옵션 c

bool findObject(Key &key, Object &found);

객체를 찾을 수없는 경우 메소드가 False를 반환합니다. 이 장점은 옵션 A의 장점은 하나의 명확한 단계에서 오류 케이스를 확인할 수 있다는 것입니다.

if (!findObject(myKey, myObj)) { ...

NULL이 예외적 인 동작으로 간주되지 않는 경우에만 참조하십시오. 나는 시도 방법에 대한 것이 분명합니다. 여기에서 언급 된 것처럼 "책을 읽거나" "도약하기 전에"를 읽을 필요가 없습니다.

그래서 기본적으로:

bool TryFindObject(RequestParam request, out ResponseParam response)

그리고 이것은 사용자의 코드도 명확하다는 것을 의미합니다.

...
if(TryFindObject(request, out response)
{
  handleSuccess(response)
}
else
{
  handleFailure()
}
...

클라이언트 코드가 찾은 것과 찾을 수없는 차이점을 알고 일상적인 행동으로 여겨지는 것이 중요하다면 NULL을 반환하는 것이 가장 좋습니다. 그런 다음 클라이언트 코드는해야 할 일을 결정할 수 있습니다.

일반적으로 NULL을 반환해야합니다. 방법을 호출하는 코드는 예외를 던질 것인지 아니면 다른 것을 시도할지 결정해야합니다.

또는 옵션을 반환하십시오

옵션은 기본적으로 고객이 부스 케이스를 처리하도록하는 컨테이너 클래스입니다. Scala는이 개념을 가지고 있습니다. API를 찾아보십시오.

그런 다음이 개체에 대한 t getorelse (t valueifnull)와 같은 메소드가 발견 된 객체를 반환하거나 클라이언트 지정을 반환합니다.

불행히도 JDK는 일관성이 없습니다. 자원 번들에서 기존 키가 아닌 키에 액세스하려고하면 예외가 발견되지 않으며 맵에서 값을 요청하면 존재하지 않으면 NULL이됩니다. 따라서 다음에 대한 우승자 답변을 변경합니다. 찾은 값이 Null이면 찾을 수없는 경우 예외를 제기하고 그렇지 않으면 NULL을 반환합니다. 따라서 한 가지 예외로 규칙을 따르십시오. 값을 찾을 수없는 이유를 알아야한다면 항상 예외를 제기하거나 ..

반환 해야하는 한 a 참조 물체에 널을 반환하는 것이 좋을 것입니다.

그러나 전혈을 반환하는 경우 (C ++처럼 : 'Return & Blah'대신 'Return Blah;'(또는 'blah'가 포인터입니다), 그렇다면 Null을 반환 할 수 없습니다. 유형 '객체'가 아닙니다.이 경우 예외를 던지거나 성공하지 못하는 빈 개체를 반환하는 것은 문제에 접근하는 방법입니다.

예외 처리에서 오버 헤드를 언급했다고 생각하지 마십시오. 진정한 앱 킬링 또는 프로세스 중지 이벤트가 아닌 한 (앞으로 나아갈 수있는 것보다 더 많은 해를 끼칠 것입니다) 나는 다시 전달할 것을 선택합니다. 호출 환경이 적합한대로 해석 할 수 있습니다.

나는 여기서 합의로 보이는 것에 동의합니다 ( "찾을 수없는 경우"가 정상적인 결과라면, 상황의 의미론이 객체를 항상 찾아야하는 경우 예외를 던집니다).

그러나 특정 상황에 따라 의미가있는 세 번째 가능성이 있습니다. 메소드는 "발견되지 않은"조건에서 어떤 종류의 기본 객체를 반환 할 수 있으므로, 호출 코드는 널 확인 또는 예외 잡기가 필요없이 항상 유효한 객체를받을 수 있도록 보장 할 수 있습니다.

널을 반환하십시오. 예외는 정확히 그렇습니다. 코드가 예상하지 못하는 것입니다.

예외가되어야합니다 특별한. 널 리턴 NULL을 반환하는 것이 유효한 경우.

귀환을 선호합니다.

발신자가 확인하지 않고 사용하는 경우 예외는 어쨌든 바로 발생합니다.

발신자가 실제로 사용하지 않으면 세금을 부과하지 마십시오. try/catch 차단하다

메소드가 컬렉션을 반환하면 빈 컬렉션을 반환합니다 (위의 Sayed와 같이). 그러나 collections.empty_list 등! (자바의 경우)

메소드가 단일 객체를 검색하면 몇 가지 옵션이 있습니다.

  1. 메소드가 항상 결과를 찾아야하고 객체를 찾지 않는 것이 실제 예외 사례라면 예외를 던져야합니다 (Java : 확인되지 않은 예외를 제발하십시오).
  2. (Java 만 해당) 메소드가 점검 된 예외를 던지는 것을 견딜 수 있다면 프로젝트 특정 ObjectNotFoundException 등을 던지십시오. 이 경우 컴파일러는 예외를 처리하는 것을 잊어 버린다고 말합니다. (이것은 Java에서 찾을 수없는 것들을 선호하는 취급입니다.)
  3. 정말 괜찮다고 말하면 객체를 찾지 못하고 메소드 이름이 findBookforAuthorOrreturnNull (..)과 같으면 NULL을 반환 할 수 있습니다. 이 경우입니다 강하게 정적 검사 또는 컴파일러 점검을 사용하는 것이 좋습니다. Java의 경우 예를 들어 할 수 있습니다. FindBugs (DefaultAnnotation at 참조 http://findbugs.sourceforge.net/manual/annotations.html) 또는 Intellij-Checking.

널을 반환하기로 결정하면 조심하십시오. 프로젝트에서 유일한 프로그래머가 아닌 경우 런타임에 NullPointerException (Java 또는 다른 언어로)을 얻게됩니다! 따라서 컴파일 시간에 확인되지 않은 널을 반환하지 마십시오.

도서관이나 예외를 던지는 다른 클래스를 사용하는 경우 재가락 그것. 여기 예입니다. example2.java는 라이브러리와 exames와 같습니다 .Java는 객체를 사용합니다. Main.java는이 예외를 처리하는 예입니다. 의미있는 메시지를 표시하고 (필요한 경우) 통화 측의 사용자에게 추적을 스택 추적해야합니다.

Main.java

public class Main {
public static void main(String[] args) {
    Example example = new Example();

    try {
        Example2 obj = example.doExample();

        if(obj == null){
            System.out.println("Hey object is null!");
        }
    } catch (Exception e) {
        System.out.println("Congratulations, you caught the exception!");
        System.out.println("Here is stack trace:");
        e.printStackTrace();
    }
}
}

예. 자바

/**
 * Example.java
 * @author Seval
 * @date 10/22/2014
 */
public class Example {
    /**
     * Returns Example2 object
     * If there is no Example2 object, throws exception
     * 
     * @return obj Example2
     * @throws Exception
     */
    public Example2 doExample() throws Exception {
        try {
            // Get the object
            Example2 obj = new Example2();

            return obj;

        } catch (Exception e) {
            // Log the exception and rethrow
            // Log.logException(e);
            throw e;
        }

    }
}

example2.java

 /**
 * Example2.java
 * @author Seval
 *
 */
public class Example2 {
    /**
     * Constructor of Example2
     * @throws Exception
     */
    public Example2() throws Exception{
        throw new Exception("Please set the \"obj\"");
    }

}

그것은 당신이 객체를 찾을 것으로 예상되는지에 달려 있습니다. 당신이 생각의 학교를 따르는 경우, 예외는 무언가를 나타내는 데 사용되어야합니다.

  • 발견 된 대상; 반환 객체
  • 객체가 발견되지 않았습니다. 예외를 던지십시오

그렇지 않으면 NULL을 반환하십시오.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top