더 나은 IllegalStateException 또는 자동 메소드 실행은 무엇입니까? [닫은]


16

play () 및 stop () 메서드가있는 MediaPlayer 클래스가 있다고 가정 해 봅시다. play 메소드가 이전에 호출되지 않은 경우 stop 메소드를 구현할 때 사용하는 가장 좋은 전략은 무엇입니까? 플레이어가 적절한 상태가 아니기 때문에 예외를 던지거나 stop 메소드 호출을 자동으로 무시하는 두 가지 옵션이 있습니다.

어떤 상황에서 메소드가 호출되지 않아야 할 때 일반적인 규칙은 무엇입니까?하지만 실행이 일반적으로 프로그램에 해를 끼치 지 않습니까?


21
예외가 아닌 행동을 모델링하는 데 예외를 사용하지 마십시오.
Alexander-복원 Monica Monica

1
야! 나는 그것이 중복이라고 생각하지 않습니다. 내 질문은 IllegalStateException에 관한 것이고 위의 질문은 일반적인 예외 사용에 관한 것입니다.
x2bool

1
그냥 조용히 실패하는 대신 왜 이상을 경고로 기록하지 않습니까? 분명히 사용중인 Java는 다른 로그 수준 (ERROR, WARN, INFO, DEBUG)을 지원합니다.
Eric Seastrand

3
항목이 이미 세트에 있으면 Set.add에서 예외가 발생하지 않습니다. 그 목적은 "항목에 세트를 추가"하는 것이 아니라 "요소가 세트에 있는지"를 확인하는 것이므로 요소가 이미 세트에있는 경우 아무 것도 수행하지 않음으로써 목적을 달성합니다.
user253751

2
오늘의 말씀 : dem 등성
Jules

답변:


37

규칙이 없습니다. API를 "느끼게"만드는 방법에 전적으로 달려 있습니다.

개인적으로, 음악 플레이어, 나는 상태에서 전환 생각 StoppedStopped방법에 의해서는 Stop()완벽하게 유효한 상태 전이이다. 그다지 의미는 없지만 유효합니다. 이를 염두에두고 예외를 던지는 것은 비공식적이고 불공평 해 보일 것입니다. 그것은 학교 버스에서 성가신 아이와 대화하는 것과 같은 사회적 느낌을 API로 만들 것입니다. 당신은 성가신 상황에 갇혀 있지만 그 문제를 해결할 수 있습니다.

보다 "연관 가능한"접근 방식은 전환이 최악의 경우에 해를 끼치며이를 허용함으로써 소비 개발자에게 친절하다는 것을 인정하는 것입니다.

따라서 그것이 나에게 달려 있다면 예외를 건너 뛸 것입니다.


15
이 답변은 때로는 간단한 상호 작용을 위해 상태 전환을 스케치하는 것이 좋습니다.

6
이를 염두에두고 예외를 던지는 것은 비공식적이고 불공평 해 보일 것입니다. 그것은 학교 버스에서 성가신 아이와 대화하는 것과 같은 사회적 느낌을 API로 만들 것입니다. > 예외는 당신을 처벌하기 위해 고안된 것이 아닙니다 : 그들은 당신에게 예기치 않은 일이 일어 났음을 말해 주도록 고안되었습니다. 필자는 개인적 으로 디버깅 코드를 몇 시간 동안 소비하고 지옥이 "아무것도 일어나지 않는"이유를 궁금해 하는 방법에 대해 매우 감사하게 생각합니다. MediaPlayer.stop()IllegalStateException
잘못된 표현

3
물론, 디자인에 루프백 전환이 유효하지 않다고 표시되면 예외가 발생합니다. 그러나 제 대답은 그러한 전환이 완벽하게 이루어지는 디자인에 관한 것이 었습니다.
MetaFight

1
StopOrThrow()끔찍하게 들린다. 그 골목을 내려 가면 표준 패턴 TryStop()? 또한 일반적으로 API의 동작이 명확하지 않은 경우 (대부분의 개발자는) 개발자가 단순히 추측하거나 실험 할 것으로 기대하지 않는 경우 문서를 살펴볼 것으로 예상됩니다. 그래서 MSDN을 너무 좋아합니다.
MetaFight

1
개인적으로 나는 fail-fast 옵션을 선호하므로 IllegalStateException을 사용하여 API 사용자에게 자신의 논리에 문제가 있음을 나타 내기 위해 IllegalStateException을 사용합니다. 나는 종종 내 자신의 코드에서 이러한 예외를 얻습니다. 정말 잘 모르는 작업이 이미 잘못되었음을 감지하는 데 도움이됩니다.
Walfrat

17

수행 할 수있는 두 가지 종류의 작업이 있습니다.

  1. 어떤 상태가 어떤 상태인지 동시에 테스트하고 다른 상태로 변경하십시오.

  2. 이전 상태에 관계없이 특정 상태로 설정하십시오.

일부 상황에서는 한 가지 조치가 필요하고 일부 상황에서는 다른 조치가 필요합니다. 콘텐츠의 끝에 도달 한 미디어 플레이어가 "재생"상태로 유지되지만 위치가 끝에서 정지 된 경우 플레이어를 "중지"로 설정 한 상태에서 플레이어가 재생 상태에 있음을 동시에 알리는 방법 상태는 코드가 중지 요청 이전에 재생이 실패하지 않도록하려는 경우에 유용 할 수 있습니다 (예 : 미디어를 한 형식에서 다른 형식으로 변환하는 수단으로 재생중인 컨텐츠를 레코딩하는 경우 중요 할 수 있음) . 그러나 대부분의 경우 중요한 것은 작동 후 미디어 플레이어가 예상 상태 (즉, 중지됨)에 있다는 것입니다.

미디어 플레이어가 미디어의 끝에 도달했을 때 자동으로 중지되는 경우 플레이어가 실행 중임을 알리는 기능이 도움이되는 것보다 더 성가 시겠지만, 경우에 따라 플레이어가 중지 된 시점에 플레이어가 실행 중인지 알면 유용한. 아마도 두 가지 요구를 모두 충족시키는 가장 좋은 방법은 함수가 플레이어의 이전 상태를 나타내는 값을 반환하도록하는 것입니다. 해당 상태를 관리하는 코드는 반환 값을 검사 할 수 있습니다. 신경 쓰지 않는 코드는 단순히 무시할 수 있습니다.


2
이전 상태를 반환하는 것에 대한 참고 사항에 대해 +1 : 전체 작업 (상태 쿼리 및 정의 된 상태로 전환)을 원자 적으로 만드는 방식으로 구현할 수 있습니다. 최소한 좋은 기능입니다. 경이로운 경쟁 조건으로 인해 산발적으로 실패하지 않는 강력한 사용자 코드를 쉽게 작성할 수 있습니다.
cmaster-monica reinstate

A bool TryStop()void Stop()코드 예제는 이것이 진정한 훌륭한 답변이 될 것입니다.
RubberDuck

2
@RubberDuck : 좋은 패턴이 아닙니다. 이 이름 TryStop은 플레이어를 강제 정지 상태로 만들 수없는 경우 예외가 발생하지 않아야 함을 의미합니다. 플레이어가 이미 중지 된 상태에서 플레이어를 중지하려고 시도하는 것은 예외적 인 조건은 아니지만 발신자가 관심을 가질 수있는 조건입니다.
supercat

1
그렇다면 귀하의 답변 @supercat을 잘못 이해했습니다.
RubberDuck

2
API가 재생 상태를 변경하지 않고 테스트 할 수있는 방법을 제공한다면이 방법을 테스트하고 설정하는 것이 데 미터 법칙을 위반하지 않는다는 것을 지적하고 싶습니다. 이것은 완전히 다른 방법 일 수 있습니다 isPlaying().
candied_orange 23시 41 분

11

일반적인 규칙은 없습니다. 이 특정한 경우, API 사용자의 의도는 플레이어가 미디어를 재생하지 못하게하는 것입니다. 플레이어가 미디어를 재생하지 않는 경우, MediaPlayer.stop()아무것도 할 수 없으며 메소드 호출자의 목표는 여전히 달성됩니다-미디어가 재생되지 않습니다.

예외를 던지면 API 사용자는 플레이어가 현재 재생 중인지 확인하거나 예외를 잡아서 처리해야합니다. 이것은 API를 사용하기에 더 번거로워합니다.


11

예외의 목적은 문제가 발생했음을 나타내는 것이 아닙니다. 그것은 신호

  1. 나쁜 일이 일어났다
  2. 여기서 고치는 법을 모르겠습니다.
  3. 호출자 또는 그로부터 호출 스택을 처리하는 방법을 알아야합니다.
  4. 따라서 손상이나 데이터 손상을 방지하기 위해 현재 코드 경로의 실행을 중단하고 호출자에게 정리를 맡겨두고

호출자가 이미 중지 된 상태에 Stop있는 MediaPlayer것을 시도하면 , 이것은 MediaPlayer해결할 수없는 문제가 아닙니다 (단순히 아무 것도 할 수 없습니다). 계속하면 손상이나 데이터로 이어질 문제는 아닙니다 단순히 아무것도하지 않으면 성공할 수 있기 때문에 부패. 그리고 발신자가 MediaPlayer. 보다 해결할 수 있기를 기대하는 것이 합리적이라는 것은 실제로 문제가되지 않습니다 .

따라서이 상황에서 예외를 발생시키지 않아야합니다.


+1. 이것이 예외가 적절하지 않은지 를 보여주는 첫 번째 대답입니다 . 예외는 발신자가 예외적 인 경우에 대해 알아야 할 가능성이 있음을 나타냅니다. 이 경우 문제의 클래스 클라이언트는 거의 확실하게 'stop ()'호출이 실제로 상태 전이를 유발했는지 여부를 신경 쓰지 않으므로 예외에 대해 알고 싶지 않을 것입니다.
Jules

5

이런 식으로보세요 :

플레이어가 재생되지 않을 때 클라이언트가 Stop ()을 호출하면 플레이어가 현재 중지 된 상태이므로 Stop ()이 자동으로 성공합니다.


3

규칙은 분석법 계약에 필요한 작업을 수행하는 것입니다.

그러한 stop방법에 대한 의미있는 계약을 정의하는 여러 가지 방법을 볼 수 있습니다 . stop플레이어가 연주하지 않는 경우 방법이 절대적으로 아무것도하지 않는 것이 완벽하게 유효 할 수 있습니다 . 이 경우 목표별로 API를 정의합니다. stopped상태 로 전환하고 싶을 때 stop메소드는 stopped오류없이 상태에서 자체로 전환하기 만하면됩니다 .

당신은 왜 어떤 이유가 원하는 예외를 던져는? 사용자 코드가 다음과 같이 보일 경우 :

try {
    player.stop();
} catch(IllegalStateException e) {
    // do nothing, player was already stopped
}

그런 예외가 있으면 이점이 없습니다. 따라서 문제는 사용자가 플레이어가 이미 중지되었다는 사실에 관심이 있습니까? 쿼리 할 다른 wa가 있습니까?

플레이어는 관찰 할 수 있습니다, 이미 어떤 일에 대한 관찰자에 통지 할 수 -가에서 transitons 때 예를 통지 관찰자 playingstoppingstopped. 이 경우, 메소드가 예외를 던지도록 할 필요는 없습니다. stop플레이어가 이미 중지 된 경우 호출 하는 것은 아무 것도 수행하지 않으며 중지되지 않은 상태에서 호출하면 관찰자에게 전환에 대해 알립니다.

대체로 논리가 끝나는 위치에 따라 다릅니다. 그러나 더 나은 디자인 선택이 있다고 생각하고 예외를 던집니다.

발신자 가 개입 해야하는 경우 예외를 처리해야합니다 . 이 경우 그는 필요하지 않습니다. 플레이어를 그대로두면 계속 작동합니다.


3

이 결정을 내리는 데 도움이되는 간단한 일반적인 전략이 있습니다.

예외가 발생하면 어떻게 처리되는지 고려하십시오.

음악 플레이어를 상상해보십시오. 사용자가 중지를 클릭 한 다음 다시 중지합니다. 해당 시나리오에서 오류 메시지를 표시 하시겠습니까? 아직 선수를 보지 못했습니다. 응용 프로그램 동작이 중지를 한 번 클릭하는 것 (이벤트 기록 또는 백그라운드에서 오류 보고서 전송)을 클릭하는 것과 다른 방식을 원하십니까? 아마 아닙니다.

즉, 예외를 잡아서 어딘가에 삼킬 필요가 있습니다. 즉 , 다른 조치를 취하고 싶지 않기 때문에 처음에는 예외를 던지지 않는 것이 좋습니다 .

이것은 예외에 그치지 않고 모든 종류의 분기에 적용됩니다. 기본적으로 행동에 관찰 가능한 차이가 필요하지 않으면 분기가 필요하지 않습니다.

즉, 중지가 "성공"인지 여부를 나타내는 또는 열거 형 값 stop()을 반환하도록 메서드를 정의하는 데 큰 해가 없습니다 boolean. 아마 그것을 사용하지는 않지만 반환 값은 예외보다 쉽고 자연스럽게 무시 될 수 있습니다.


2

여기에 얼마나 안드로이드를 수행합니다 MediaPlayer를

간단히 말해서, stopstart호출되지 않은 문제는 심지어이 재생되는 것을 알고하지 않는 선수로 불려 갔을 경우 호출하기위한 좋은 이유가 없기 때문에, 정지 상태에서 시스템 숙박이 있지만, 예외가 throw됩니다 아니다 거기서 멈춰


1

어떤 상황에서 메소드가 호출되지 않아야 할 때 일반적인 규칙은 무엇입니까?하지만 실행이 일반적으로 프로그램에 해를 끼치 지 않습니까?

나는 당신의 진술에서 당신에게 명확한 답을 줄 수있는 사소한 모순이 무엇인지 봅니다. 왜 메소드가 호출되지 않아야 하지만 실행이 해를 끼치 지 않는 이유는 무엇 입니까?

왜 메소드가 "호출되지 않아야"합니까? 그것은 스스로 부과 한 제한처럼 보입니다. "유해"가 없거나 API에 영향을주는 경우 예외는 없습니다. 유효하지 않거나 예측할 수없는 상태를 생성 할 수 있으므로 메소드를 실제로 호출하지 않으면 예외가 발생해야합니다.

예를 들어, DVD 플레이어로 걸어 가서 "시작"을 누르기 전에 "중지"를 눌렀을 때 충돌이 발생하면 말이되지 않습니다. 화면에 앉아 있거나 더 나쁜 경우 화면에서 "중지"를 인식해야합니다. 오류는 성가 시며 어떤 식 으로든 도움이되지 않습니다.

그러나 이미 꺼져있을 때 (메소드를 호출 할 때) 알람 코드를 넣어서 "끄기"하여 나중에 제대로 작동하지 못하게하는 상태가 될 수 있습니까? 그렇다면 나중에 문제가 발생할 수 있기 때문에 기술적으로 "손상이 없었습니다"라는 오류가 발생하더라도 오류가 발생합니다. 실제로 그 상태로 들어 가지 않더라도 이것에 대해 알고 싶습니다. 가능성만으로 충분합니다. 이것은입니다 IllegalStateException.

귀하의 경우, 상태 시스템이 유효하지 않은 / 불필요 한 호출을 처리 할 수 ​​있다면 무시하고 그렇지 않으면 오류를 발생시킵니다.

편집하다:

값을 검사하지 않고 변수를 두 번 설정하면 컴파일러에서 오류가 발생하지 않습니다. 또한 변수를 다시 초기화하는 것을 방해하지 않습니다. 한 가지 관점에서 "버그"로 간주 될 수있는 많은 동작이 있지만 단지 "비효율적", "불필요한", "무의미한"등입니다. 나는 내 대답에 그러한 관점을 제공하려고 노력했습니다. 이러한 일을하는 것은 일반적으로 고려되지 않습니다 "버그"는 예기치 않은 결과를 초래하지 않기 때문입니다. 아마도 비슷한 방식으로 문제에 접근해야합니다.


호출하면 호출자의 버그를 나타내므로 호출되지 않아야합니다.
user253751

@immibis : 반드시 그런 것은 아닙니다. 예를 들어, 해당 발신자는 일부 UI 버튼의 클릭시 리스너 일 수 있습니다. (사용자는 미디어가 이미 중지 된 경우 실수로 중지 버튼을 클릭하면 오류 메시지를 원하지 않을 것입니다.)
meriton

@meriton UI 버튼의 클릭시 리스너라면, "버튼을 눌렀을 때 어떤 일을 하든지"대답이 분명합니다. 분명히 그것은 응용 프로그램 내부의 것이 아닙니다.
user253751 2016 년

@immibis-응답을 편집했습니다. 도움이 되길 바랍니다.
Jim

1

정확히 무엇을 MediaPlayer.play()하고 MediaPlayer.stop()수행합니까?- 사용자 입력을위한 이벤트 리스너 입니까, 아니면 실제로 시스템에서 일종의 미디어 스트림을 시작하는 방법입니까? 이들이 모두 사용자 입력을위한 청취자라면 아무 것도하지 않는 것이 합리적입니다 (적어도 어딘가에 기록하는 것이 좋습니다). 그들이 영향을 미치는 경우, 모델 당신의 UI가 제어되어, 그들은은을 던질 수있는 IllegalStateException선수가 몇 가지의 종류가 있어야하기 때문에 isPlaying=true또는 isPlaying=false상태 (이 여기에 기록 된 같은 실제 부울 플래그를 할 필요가 없다), 그래서 당신이 호출 할 때 MediaPlayer.stop()경우 isPlaying=falseMediaPlayer객체가 중지 될 적절한 상태에 있지 않으므로 메소드가 실제로 "중지"할 수 없습니다 .java.lang.IllegalStateException 수업:

불법적이거나 부적절한 시간에 메소드가 호출되었음을 나타냅니다. 즉, Java 환경 또는 Java 응용 프로그램이 요청 된 작업에 적합한 상태가 아닙니다.

예외를 던지는 것이 좋은 이유

많은 사람들은 예외가 발생해서는 안되는 것처럼 일반적으로 예외가 나쁘다고 생각하는 것 같습니다 (참조 : Joel on Software ). 그러나 당신이이 말을 MediaPlayerGUI.notifyPlayButton()하는 전화 MediaPlayer.play()MediaPlayer.play()원용하는 다른 코드는 예와 인터페이스 어딘가에 선을 아래 한 무리의 펄스 오디오를 ,하지만 난 모든 코드가 작성하지 않았기 때문에 I (개발자)는 어디 모른다.

그런 다음 어느 날 코드 작업을하는 동안 "재생"을 클릭하면 아무 일도 일어나지 않습니다. MediaPlayerGUIController.notifyPlayButton()뭔가를 기록 하면 적어도 로그를 살펴보고 버튼 클릭이 실제로 등록되었는지 확인할 수 있지만 왜 재생되지 않습니까? 실제로 PulseAudio 래퍼에 문제가 있다고 가정 해보십시오 MediaPlayer.play(). "재생"버튼을 다시 클릭하면 이번에는 IllegalStateException:

 Exception in thread "main" java.lang.IllegalStateException: MediaPlayer already in play state.

     at org.superdupermediaplayer.MediaPlayer.play(MediaPlayer.java:16)
     at org.superdupermediaplayer.gui.MediaPlayerGUIController.notifyPlayButton(MediaPlayerGUIController.java:25)
     at org.superdupermediaplayer.gui.MediaPlayerGUI.main(MediaPlayerGUI.java:14)

스택 추적을 보면 MediaPlayer.play()디버깅 하기 전에 모든 것을 무시 하고 오디오 스트림을 시작하기 위해 PulseAudio로 메시지가 전달되지 않는 이유를 알아내는 데 시간을 할애 할 수 있습니다 .

반면에, 예외를 던지지 않는다면 , "어리석은 프로그램은 어떤 음악도 연주하지 않습니다."; 비록하지 명시 적으로 나쁜 같은 오류 숨기기실제로 예외 삼키는 사실에 던져 , 당신은 여전히 잠재적으로 뭔가 이동 잘못을하지 다른 사람의 시간을 낭비를 ... 너무 좋은 그들에 예외를 throw합니다.


0

소비자가 실수하기가 어렵거나 불가능한 방식으로 API를 디자인하는 것을 선호합니다. 예를 들어, MediaPlayer.play()및 대신에 "중지됨"과 "재생 중"사이를 전환 MediaPlayer.stop()할 수 있습니다 MediaPlayer.playToggle(). 이 방법을 사용하면 항상 호출이 안전합니다. 불법 상태가 될 위험은 없습니다.

물론 이것이 항상 가능하거나 쉬운 것은 아닙니다. 당신이 준 예제는 이미 목록에서 제거 된 요소를 제거하는 것과 비슷합니다. 당신은 둘 중 하나 일 수 있습니다

  • 그것에 대해 실용적이고 오류가 발생하지 않습니다. 이것은 확실히 많은 코드를 단순화합니다 (예 : if (list.contains(x)) { list.remove(x) }필요한 것만 쓰는 대신 list.remove(x)). 그러나 버그를 숨길 수도 있습니다.
  • 또는 pedantic하고 목록에 해당 요소가 포함되어 있지 않다는 오류를 표시 할 수 있습니다. 메소드를 호출하기 전에 사전 조건이 충족되는지 지속적으로 확인해야하기 때문에 코드가 더 복잡해질 수 있지만, 단점은 최종 버그를 쉽게 추적 할 수 있다는 것입니다.

MediaPlayer.stop()이미 중지되었을 때 호출 하면 응용 프로그램에 아무런 영향을 미치지 않으면 코드를 단순화하고 dem 등식 메소드가 있기 때문에 자동으로 실행하도록하겠습니다. 그러나 MediaPlayer.stop()그 조건에서 절대 호출되지 않을 것이 확실하다면 코드의 다른 곳에 버그가있을 수 있고 예외를 추적하는 데 도움이되므로 오류가 발생합니다.


3
playToggle()사용하기 쉽다 는 것에 동의하지 않습니다 . 원하는 효과 (플레이어 재생 또는 재생하지 않음)를 달성하려면 현재 상태를 알아야합니다. 따라서 플레이어 중지를 요청하는 사용자 입력을 받으면 먼저 플레이어가 현재 재생 중인지 문의 한 다음 답변에 따라 상태를 전환해야합니다. stop()메소드를 호출하는 것보다 훨씬 번거 롭습니다 .
cmaster-monica reinstate

글쎄 나는 사용하기가 더 쉽다고 말한 적이 없다. 내 주장은 그것이 더 안전하다는 것이었다. 또한, 예제에서는 사용자에게 별도의 중지 및 재생 버튼이 제공된다고 가정합니다. 그것이 사실이라면 그렇습니다 playToggle.a 사용하기가 매우 번거로울 것입니다. 그러나 사용자에게 대신 토글 버튼이 제공되면 playToggle재생 / 정지보다 사용하기가 더 쉽습니다.
Pedro Rodrigues
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.