가독성을 높이기 위해“예외 잡기”를 사용 하는가?


9

섹션에서 사용 예외에실용주의 프로그래머 , 책 쓰기 대신의 :

retcode = OK;
     if (socket.read(name) != OK) {
      retcode = BAD_READ;
    }
     else {
      processName(name);
       if (socket.read(address) != OK) {
        retcode = BAD_READ;
      }
       else {
        processAddress(address);
         if (socket.read(telNo) != OK) {
          retcode = BAD_READ;
        }
         else {
          //  etc, etc...
        }
      }
    }
     return retcode;

, 그들은 선호한다:

 retcode = OK;
     try {
      socket.read(name);
      process(name);
      socket.read(address);
      processAddress(address);
      socket.read(telNo);
      //  etc, etc...
    }
     catch (IOException e) {
      retcode = BAD_READ;
      Logger.log( "Error reading individual: " + e.getMessage());
    }
     return retcode;

더 깔끔해 보이기 때문입니다. 난 모든 그러나 성능 병목 예외 잡는 필요없는, 깔끔한 코드를?

나는 우리가 더 깔끔한 코드 (최소한 99 %)에 대한 최소한의 최적화를 포기해야한다는 것을 이해할 수 있지만, 예외를 잡는 것은 런타임에 눈에 띄게 지연되는 코드 클래스에 속합니다. 따라서 두 번째 코드가 첫 번째 코드보다 선호된다는 정당성이 무엇인지 궁금합니다.

아니면 어느 코드를 선호합니까?


코드 검토 질문이 아니라 모범 사례 질문으로 코드 검토에서 마이그레이션
Winston Ewert

1
IMO, 소켓에서 그 값을 읽을 것으로 기대된다면 IOEx 예외적입니다.
Steven Evers


측정 했습니까?

@ ThorbjørnRavnAndersen은 물론이 책을 읽고 측정 할 실제 "테스트 사례"를 가지고 있지 않습니다. 그러나 우리가
결정된

답변:


18

예외는 실제로 실제로 발생하는 경우에만 느려집니다. 일반적으로 이와 같은 상황의 예외는 드물기 때문에 걱정할 것이 없습니다. 예외가 항상 발생하여 중요한 요소 인 경우에만 예외 성능에 대해 걱정해야합니다.

두 번째 코드는 논리를 따르기가 훨씬 쉽기 때문에 더 좋습니다. 오류 처리가 잘 현지화되었습니다. 유일한 반대는 예외를 사용하는 경우 예외를 사용한다는 것입니다. 예외를 포착하지 말고 오류 코드를 리턴하십시오.


4
동의합니다. 예외가있는 언어로 오류 코드를 보는 것이 싫습니다. 대부분의 경우 통화 스택 중단 하지 않고 잡아서 기록하고 다시 던져야 합니다. 대부분의 경우 "예외"사례가 더 느린 경우에는 문제가되지 않습니다. 앱에 문제가 있습니다. 제대로 처리하려면 시간이 걸립니다. 예외가 예외적이며 응용 프로그램의 정상적인 작동 또는 행복한 경로의 일부가 아닌 한 일반적으로 코드 냄새가 아닙니다.
CaffGeek

Btw docs.oracle.com/javase/tutorial/essential/io/datastreams.html에 설명 된 것처럼 DataStreams가 줄 끝을 감지하는 데 사용하는 EOFException을 어떻게 정당화하는지 궁금합니다. ?
Pacerier

@Pacerier, 예외적 일 수 있습니다. 라인에 입력이 부족하면 데이터가 잘못되었거나 잘못 될 수 있습니다. 의도 된 용도가 여러 필드를 한 줄에서 구문 분석하는 것으로 생각됩니다.
Winston Ewert

@Downvoter, 답변에 문제가 있으면 설명하십시오!
Winston Ewert

5

글쎄, 그들이 말했듯이 예외는 예외적 인 경우를 처리해야 하며 예외적 인 경우 (즉, 거의 발생하지 않는 것)이므로 여기에도 적용된다고 말하고 싶습니다.

또한, 나는 이와 같은 미세 최적화 에 대해 조언 합니다. 새 코드를 작성하는 것보다 코드를 읽는 데 훨씬 많은 시간을 소비하므로 코드의 가독성에 더 집중하십시오 .

이것이 성능 병목 현상인지 확인하려면 프로파일 링을 수행하고 해당 분석을 기반으로 더 중요한 작업에 분석하고 집중하십시오.


5

나는 우리가 더 깔끔한 코드 (최소한 99 %)에 대한 최소한의 최적화를 포기해야한다는 것을 이해할 수 있지만, 예외를 잡는 것은 런타임에 눈에 띄게 지연되는 코드 클래스에 속합니다.

어디서 알았습니까? "알릴 수있는 지연"을 어떻게 정의합니까?

이것은 쓸모없는 조기 최적화로 이어지는 모호한 (그리고 완전히 잘못된) 퍼포먼스 신화입니다.

예외를 던지고 잡는 것은 두 개의 숫자를 추가하는 것에 비해 느릴 수 있지만 소켓에서 데이터를 읽는 것과 비교할 때 완전히 중요하지 않습니다 . 단일 네트워크 패킷을 읽는 동시에 수천 개의 예외를 처리 할 수 ​​있습니다. 그리고 우리는 여기서 수천 가지 예외에 대해 이야기하지 않고 단 하나의 예외 만 이야기합니다.


나는 .NET에서 왔기 때문에 Java에 대한 지식을 용서하지만 개인적으로 .NET에서 예외를 발견하여 "catching-exception code"를 제거하여 수정 된 미친 지연 (단위 : 초)을 경험했습니다.
Pacerier

@Pacerier, 진심으로? 초 크기? 아마 많은 예외를 잡는 것 같아요? 그때 나는 그것을 볼 수 있었다.
Winston Ewert

3
@Pacerier : 예외가 미친 지연을 일으키는 경우 예외를 일으키는 원인은 예외가 아니므로 다른 방식으로 처리해야합니다. 어떤 시스템도 예외를 처리하는 데 몇 초가 걸리지 않으며 Microsoft는이를 피할 수있는 충분한 능력이 있다고 생각합니다.
David Thornley

5

나는 이것이 예외적 인 경우라는 이미 얻은 답변에 동의하므로 예외 처리를 사용하는 것이 합리적입니다.

성능 문제를보다 직접적으로 다루기 위해서는 사물에 대한 스케일 감각을 유지해야한다고 생각합니다. 이러한 상황에서 예외를 던지거나 잡는 것은 1 마이크로 초 정도 걸릴 수 있습니다. 흐름 제어에도 있듯이, 그 없습니다 느린 - 여러 번 느리게 평소보다 if문, 그것에 대해 의심.

동시에 여기서하는 일은 네트워크에서 데이터를 읽는 것입니다. 초당 10 메가 비트 (로컬 네트워크의 경우 느리지 만 인터넷 연결의 속도는 매우 빠름)로, 이는 1 바이트 의 정보 를 읽는 시간과 같은 순서 입니다.

물론, 오버 헤드는 실제로 예외를 던질 때만 발생합니다-예외가 발생하지 않으면 일반적으로 오버 헤드가 거의 없거나 전혀 없습니다 (적어도 내가 본 것에서 가장 중요한 오버 헤드는 잠재적 인 제어 흐름을 추가하여 컴파일러가 코드를 최적화하는 것을 더욱 어렵게 만드는 예외 처리 자체).

이 경우 예외가 발생하면 데이터를 로그에 기록합니다. 로깅의 특성상, 출력을하자마자 플러싱 할 가능성이 매우 높습니다 (손실되지 않도록). 디스크에 쓰는 작업은 상당히 느리게 진행됩니다. 초당 수만 IOP의 범위에 도달하려면 상당히 빠른 엔터프라이즈 급 SSD가 필요합니다. 로깅에 사용되는 디스크는 초당 수백 IOP와 같은 것으로 쉽게 제한 될 수 있습니다.

결론 : 예외 처리 오버 헤드 가 중요 할 수 있는 경우가 있지만 거의 확실하게 그중 하나 가 아닙니다 .

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