개인 메소드에서 인수 예외 또는 인수 무효화를 처리합니까?


20

방금 쓴 일부 코드를 검토하고 있었으며, 메소드 매개 변수에 문제가있는 경우 인수 nullexceptions 및 / 또는 argumentexceptions을 발생시키는 몇 가지 개인 메소드가 있음을 알 수 있습니다.

내 이론적 근거는 누군가가 미래에 방법을 "오용"하려고 할 경우 응용 프로그램을 나중에 증명하는 데 도움이된다고 생각합니다. 그러나 개인 메소드 이며이 메소드를 호출 할 가능성이있는 사람들은 관련 주석과 코드를 볼 수 있으므로이를 던질 필요는 없습니다. 그것은 혼란을 추가하지만 확실히 그들을 아프게하지 않습니다.

내 생각에 이러한 예외는 일반적으로 공개적으로 공개 될 API와 같은 것에 더 유용합니다.

답변:


22

일반적으로 개인 메소드의 경우 예외를 작성하지 않았으므로 개발자는 메소드를 호출하는 방법과 위치를 알고 있어야합니다. 따라서 개인 메소드에 매개 변수로 전달 된 변수는 메소드 외부에서, 즉 호출하기 전에 점검해야합니다. "InvalidArgumentException"및 기타 예외를 발생시키는 것은 공용 메소드 ( "API"작성 여부)에 대한 우수 사례로 간주됩니다.

"InvalidArgumentException"을 발생시키려는 경우 Assert버전 1.1.2부터 Java 용 Spring API에 클래스 가 있다고 언급 할 가치가 있습니다. 검사를 수행하기 위해 적은 코드를 작성하는 데 도움이되었습니다.

그러나 "어설 션"을 사용하여 개인용 메소드에서 매개 변수를 확인할 수 있습니다. 그것이 그들의 진정한 목적 중 하나입니다. 그것들을 사용해야하는 더 많은 이유가 있습니다. 어설 션 사용시기와 예외 사용시기를 자세히 설명 하는 다음 링크 를 확인하십시오 . 어설 션은 프로덕션 코드에 포함되지 않으며 컴파일러는 기본적으로 제거합니다. 그래서 그들은 당신이 찾고있는 것입니다 : 개발자에게 도움이되고 사용자에게는 보이지 않습니다. Java에서는 특수 플래그 ( "-ea")를 사용하여 컴파일러에 어설 션을 활성화하도록 지시해야합니다. 당신은 "파괴"친구로 간주 할 수 있습니다.

assert를 사용하는 방법은 다음과 같습니다.


1
아파치 코 몬즈는 또한 유효성 검사 클래스가 그 봄의 어설 클래스에 유사 기능
로사 리히터

@cantido 네, 구글 구아바의 Preconditions 클래스도 같은 방식으로 작동한다고 덧붙였습니다. 정보 주셔서 감사합니다 :-)
Jalayn

2

다른 모든 것들처럼 그것은 의존합니다 ....

퍼블릭 메소드가 프라이빗 오버로드 된 메소드의 행을 따라 프라이빗 메소드를 호출하는 단순 랩퍼 인 경우 각 퍼블릭 메소드를 체크인하는 대신 프라이빗 메소드에서 예외를 발생시키는 것이 좋습니다.

일반적으로 위의 정의를 충족하지 않으면 일반적으로 인수를 확인하지 않고 개인 메서드에서 예외를 throw하지 않습니다. 다른 경우가 있지만 일반적으로 인수가 유효하지 않은 경우 부분적으로 실패 할 수있는 비싼 작업을 수행하기 전에 개인 방법 으로이 작업을 수행합니다.


2

질문에 언어 태그가 없지만 "커피 언어"에 대해 암묵적으로 이야기하고 있음을 알고 있습니다. 그러나 완전성을 위해 C ++ 세계에서 다소 다른 명백한 합의를 언급하고 싶습니다.

C ++ 프로그래머가 일반적으로 관심을 가질만한 세 가지 사항이 있습니다.

  • 최적화 된 빌드에서 오버 헤드가 없습니까? (즉,“컴파일”할 수 있습니까?)
  • 오류가 감지 된 시점에서이를 사용하여 디버거에 트랩 할 수 있습니까?
  • 선언 된 함수의 문제를보고하는 데 사용할 수 있습니까 noexcept?

과거에는 다음과 같은 코드를 작성하여 첫 번째 문제에 접근했습니다.

int
factorial(const int n)
{
  if (CHECK_ARGS)
    {
      if (n < 0)
        throw std::invalid_argument {"n < 0"};
    }
  int fac = 1;
  for (int i = 2; i <= n; ++i)
    fac *= i;
  return fac;
}

여기서 CHECK_ARGS된다 #define컴파일러 완전히 모든 인수 검사 코드를 제거 할 수 있도록 컴파일 시간 상수 거라고 최적화 만든다. (체크 아웃을 컴파일하는 것이 일반적으로 좋은 것이라고 말하지는 않지만 사용자 에게 옵션이 있어야한다고 생각합니다. 컴파일 할 수 이 .)

인수 확인 코드가 명확하게 함께 그룹화되어 표시되는이 솔루션에 대해 여전히 맘에 듭니다 if. 그러나 두 번째 및 세 번째 문제는 이것으로 해결되지 않습니다. 따라서 assert인수 확인을 위해 매크로를 사용하는 데 더 집중 하고 있습니다.

코딩 표준 부스트는 이 동의 :

프로그래머 오류는 어떻습니까?

개발자로서 내가 사용하는 라이브러리의 전제 조건을 위반 한 경우 스택 풀기를 원하지 않습니다. 내가 원하는 것은 코어 덤프 또는 동등한 것입니다. 문제가 감지 된 정확한 시점에서 프로그램의 상태를 검사하는 방법입니다. 그것은 보통 그 assert()와 같은 것을 의미 합니다.

에서 존 Lakos에 의해 주어진 매우 흥미로운 이야기가 있었다 CppCon'14는 제목의 오른쪽을 완료 방어 프로그래밍 ( 1 부 , 2 부 ). 대화의 첫 부분에서 그는 계약 이론과 정의되지 않은 행동에 대해 논의합니다. 두 번째 부분에서, 그는 체계적인 인수 확인을위한 아주 좋은 제안을 제시합니다. 본질적으로, 그는 사용자가 인수 확인을 위해 라이브러리에 기부 할 예산의 양 (CPU 사용률 측면에서)을 선택할 수있는 어설 션 매크로를 제안하고 라이브러리가 해당 예산을 현명하게 사용하도록합니다. 또한, 사용자는 계약이 깨졌을 때 호출되는 전역 오류 처리 기능을 설치할 수도 있습니다.

함수가 개인이라는 측면에 관해서는 이것이 인수를 확인 해서는 안된다는 것을 의미하지는 않습니다 . 내부 함수의 계약을 위반하지 않기 위해 자체 코드를 더 신뢰할 수도 있지만 완벽하지 않다는 것도 알고 있습니다. 내부 함수의 인수 검사는 클라이언트 코드에서 버그를 감지하는 공용 함수에서와 마찬가지로 자체 버그를 감지하는 데 도움이됩니다.


1

다음 구조를 고려하십시오.

  1. 내부 논리 :이 함수는 올바른 매개 변수를 사용하여 호출되는 것으로 가정하므로 어설 션을 사용하여 사전 조건, 사후 조건 및 불변량을 확인하여 내부 논리를 확인합니다.

  2. 사용자 인터페이스 래퍼 :이 기능은 내부 함수를 래핑하고 InvalidArgumentExceptions 잘못된 값을 처리하고 자신의 입력을 해결하기 위해 사용자에게 사용 : Assert(x).hasLength(4);, Assume(y).isAlphanumeric();, Assert(z).isZipCode();, Assume(mailAdress).matchesRegex(regex_MailAdress);, Reject(x).ifEmpty();, 등

  3. 배치 인터페이스 랩퍼 :이 기능은 내부 기능을 랩핑하고 로깅, 유효성 표시 및 통계를 사용하여 장기 실행 태스크를 방해하지 않고 잘못된 값을 처리합니다. 결과 데이터베이스를 확인하고 청소하는 사람이 나중에 표시를 사용할 수 있습니다.

  4. 명령 행 인터페이스 랩퍼 :이 함수는 내부 함수를 랩핑하고 마지막 입력을 다시 요청합니다.

다양한 작업에 대해 다른 방법으로 주장과 예외를 모두 사용해야합니다. 내부 논리를 매개 변수 확인과 분리해야합니다. 모델, 뷰, 컨트롤러의 분리와 비교하십시오.


0

null 참조 확인을 피하는 더 좋은 방법이 있습니다. 코드 계약 또는 AOP 프레임 워크를 사용하여 확인하십시오. Google "C # 코드 계약"또는 "postsharp"


내 질문은 코드 계약으로 확장 될 것이라고 생각합니다. 사적인 방법으로 방법 전제 조건을 점검해야합니까 (예 : 향후 교정 또는 발로 자신을 쏘지 못하게 막기 위해)?
Mr Moose
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.