[java] “while (true)”루프가 그렇게 나쁩니 까? [닫은]

저는 몇 년 동안 Java로 프로그래밍을 해왔지만 최근에 정규 학위를 받기 위해 학교로 돌아 왔습니다. 마지막 과제에서 아래의 루프와 같은 루프를 사용하면 포인트를 잃어 버렸다는 사실에 놀랐습니다.

do{
     //get some input.
     //if the input meets my conditions, break;
     //Otherwise ask again.
} while(true)

이제 테스트를 위해 콘솔 입력을 스캔하고 있지만 사용 break이 비슷하기 때문에 이런 종류의 루프는 권장하지 않는다는 말을 들었 goto습니다.

나는 함정 goto과 그 자바 사촌을 완전히 이해 하고 있으며 break:label, 그것을 사용하지 않는 것이 좋습니다. 또한 더 완전한 프로그램이 다른 탈출 수단을 제공한다는 것을 알고 있습니다.

무슨 일이야 do-while(true)?



답변

나는 그것이 나쁘지 않다고 말하지 않을 것입니다 -그러나 마찬가지로 나는 대체로 적어도 대안을 찾습니다.

그것이 내가 쓰는 첫 번째 상황 인 경우, 나는 거의 항상 그것을 더 명확한 것으로 리팩토링 하려고 시도 합니다. 때로는 도움이되지 않을 수도 있습니다 (또는 대안은 bool루프의 끝을 나타내지 않고 의미가없는 변수 를 갖는 것 break입니다.)

break플래그보다 사용하기 쉬운 곳의 예로 다음을 고려하십시오.

while (true)
{
    doStuffNeededAtStartOfLoop();
    int input = getSomeInput();
    if (testCondition(input))
    {
        break;
    }
    actOnInput(input);
}

이제 플래그를 사용하도록하겠습니다 :

boolean running = true;
while (running)
{
    doStuffNeededAtStartOfLoop();
    int input = getSomeInput();
    if (testCondition(input))
    {
        running = false;
    }
    else
    {
        actOnInput(input);
    }
}

나는 후자를 읽기가 더 복잡하다고 생각합니다 : 여분의 else블록이 있고, actOnInput들여 쓰기가 더되며 , testCondition반환 할 때 발생하는 일을 해결하려는 경우 true블록의 나머지 부분을주의 깊게 살펴보고 거기에 있는지 확인해야합니다. 뭔가가 아니다else 여부를 발생할 수있는 블록 running으로 설정되어 false여부.

break진술은 의도를보다 명확하게 전달하고 나머지 블록은 이전 조건에 대해 걱정하지 않고 필요한 작업을 수행 할 수 있도록합니다.

이것은 사람들이 메소드에서 여러 개의 return 문에 대해 갖는 것과 동일한 종류의 인수입니다. 예를 들어, 처음 몇 줄 내에서 메소드의 결과를 계산할 수있는 경우 (예 : 일부 입력이 null이거나 비어 있거나 0 인 경우) 결과를 저장할 변수를 갖는 것보다 해당 답변을 직접 반환하는 것이 더 명확합니다. 그런 다음 다른 코드의 전체 블록과 마지막 으로 return명령문.


답변

AFAIK 아무것도 아닙니다. 교사는에 대한 알레르기가 있습니다 goto. 왜냐하면 어딘가 나쁜 소식을 들었 기 때문입니다. 그렇지 않으면 다음과 같이 작성합니다.

bool guard = true;
do
{
   getInput();
   if (something)
     guard = false;
} while (guard)

거의 같은 것입니다.

어쩌면 이것은 더 깨끗합니다 (모든 반복 정보가 블록의 상단에 포함되어 있기 때문에) :

for (bool endLoop = false; !endLoop;)
{

}


답변

Douglas Crockford는 JavaScriptloop구조가 포함 되기를 원하는 방식에 대해 언급했습니다 .

loop
{
  ...code...
}

그리고 나는 Javaloop구조 를 갖는 데 더 나쁜 것이라고 생각하지 않습니다 .

while(true)루프에는 본질적으로 아무런 문제가 없지만 교사 루프 를 방해하는 경향이 있습니다. 교수의 관점에서 볼 때 학생들이 끝없는 루프를 만들고 루프가 탈출하지 않은 이유를 이해하게하는 것은 매우 쉽습니다.

그러나 그들이 거의 언급하지 않는 것은 모든 루핑 메커니즘이 while(true)루프 로 복제 될 수 있다는 것 입니다.

while( a() )
{
  fn();
}

와 같다

loop
{
  if ( !a() ) break;
  fn();
}

do
{
  fn();
} while( a() );

와 같다:

loop
{
  fn();
  if ( !a() ) break;
}

for ( a(); b(); c() )
{
  fn();
}

와 같다:

a();
loop
{
  if ( !b() ) break;
  fn();
  c();
}

사용하도록 선택한 구문이 작동 하는 방식으로 루프를 설정할 수있는 한 중요하지 않습니다. 이 경우 발생 에 맞게 for루프하는을 사용for 루프를.

마지막 부분 : 루프를 단순하게 유지하십시오. 반복 할 때마다 많은 기능이 필요한 경우 기능에 넣으십시오. 작동 후에는 항상 최적화 할 수 있습니다.


답변

1967 년에 Edgar Dijkstra는 무역 잡지에 기사를 작성하여 코드 품질을 향상시키기 위해 고급 언어에서 goto를 제거해야하는 이유를 설명했습니다. “구조적 프로그래밍”이라고하는 전체 프로그래밍 패러다임은 이것에서 나온 것이지만 모든 사람이 자동으로 잘못된 코드를 의미한다고 동의하는 것은 아닙니다.

구조적 프로그래밍의 요점은 본질적으로 코드 구조가 가능한 한 흐름을 결정하거나 중단하지 않고 흐름을 결정해야한다는 것입니다. 마찬가지로 패러다임에서는 루프 나 함수에 여러 개의 진입 점과 출구 점이있는 것도 권장하지 않습니다.

분명히 이것이 유일한 프로그래밍 패러다임은 아니지만 종종 객체 지향 프로그래밍 (ala Java)과 같은 다른 패러다임에 쉽게 적용될 수 있습니다.

귀하의 교사는 아마도 가르쳐 졌을 것입니다. 그리고 코드를 체계화하고 구조화 된 프로그래밍의 암묵적인 규칙을 준수하여 “스파게티 코드”를 피하는 것이 가장 좋습니다.

break를 사용하는 구현에는 본질적으로 “잘못”된 것이 없지만 while () 조건 내에 루프 조건이 명시 적으로 지정되어 지나치게 까다로울 수있는 가능성을 제거하는 코드를 읽는 것이 훨씬 쉽다고 생각하는 사람들도 있습니다. 실수로 무한 루프를 생성하거나 읽기가 어렵거나 불필요하게 혼동되는 코드를 만드는 위험과 같은 초보 프로그래머가 코드에 자주 나타나는 것처럼 보이는 while (true) 조건을 사용하는 데에는 분명히 함정이 있습니다.

아이러니하게도 예외 처리는 구조적 프로그래밍과의 편차가 확실하게 나타나고 Java 프로그래밍에 더 나아갈 때 예상되는 영역입니다.

또한 강사는 해당 장 또는 텍스트 레슨에서 가르치는 특정 루프 구조 또는 구문을 사용하는 능력을 보여줄 것으로 예상했을 수도 있으며, 작성한 코드는 기능적으로 동일하지만 그 레슨에서 배웠어야했던 특정 기술.


답변

입력을 읽기위한 일반적인 Java 규칙은 다음과 같습니다.

import java.io.*;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String strLine;

while ((strLine = br.readLine()) != null) {
  // do something with the line
}

그리고 입력을 읽는 일반적인 C ++ 규칙은 다음과 같습니다.

#include <iostream>
#include <string>
std::string data;
while(std::readline(std::cin, data)) {
  // do something with the line
}

그리고 C에서는

#include <stdio.h>
char* buffer = NULL;
size_t buffer_size;
size_t size_read;
while( (size_read = getline(&buffer, &buffer_size, stdin)) != -1 ){
  // do something with the line
}
free(buffer);

또는 파일에서 가장 긴 텍스트 줄이 얼마나 긴지 알고 있다면

#include <stdio.h>
char buffer[BUF_SIZE];
while (fgets(buffer, BUF_SIZE, stdin)) {
  //do something with the line
}

사용자가 quit명령을 입력했는지 여부를 테스트하는 경우 이러한 3 가지 루프 구조를 쉽게 확장 할 수 있습니다. 나는 당신을 위해 자바로 할 것입니다 :

import java.io.*;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line;

while ((line = br.readLine()) != null  && !line.equals("quit") ) {
  // do something with the line
}

따라서 확실히 break또는 goto정당화 되는 경우가 있지만 파일이나 콘솔에서 한 줄씩 읽는 것이면 while (true)루프를 수행 할 필요가 없습니다. 프로그래밍 언어가 이미 제공 한 것입니다 입력 명령을 루프 조건으로 사용하기위한 적절한 관용구.


답변

그렇게 끔찍한 것은 아니지만 코딩 할 때 다른 개발자를 고려해야합니다. 심지어 학교에서도.

동료 개발자는 루프 선언에서 루프의 exit 절을 볼 수 있어야합니다. 당신은 그렇게하지 않았습니다. 루프 중간에 exit 절을 숨겨서 코드를 이해하려고 시도하는 다른 사람을 위해 더 많은 작업을 수행합니다. 이것이 “break”와 같은 것을 피하는 것과 같은 이유입니다.

즉, 실제 세계의 많은 코드에서 여전히 이와 같은 것을 볼 수 있습니다.


답변

총, 총알, 발입니다.

당신이 문제를 요구하기 때문에 나쁘다. 짧거나 단순한 while 루프 예제가있는이 페이지의 사용자 나 다른 포스터는 아닙니다.

문제는 앞으로 매우 임의의 시간에 시작됩니다. 다른 프로그래머가 원인 일 수 있습니다. 소프트웨어를 설치 한 사람 일 수 있습니다. 최종 사용자 일 수 있습니다.

왜? 700K LOC 앱이 모든 CPU가 포화 될 때까지 점차적으로 CPU 시간의 100 %를 레코딩하기 시작하는 이유를 찾아야했습니다. 그것은 놀라운 while (true) 루프였습니다. 크고 불쾌했지만 다음과 같이 정리했습니다.

x = read_value_from_database()
while (true)
 if (x == 1)
  ...
  break;
 else if (x ==2)
  ...
  break;
and lots more else if conditions
}

마지막으로 다른 지점은 없었습니다. 값이 if 조건과 일치하지 않으면 루프는 시간이 끝날 때까지 계속 실행됩니다.

물론 프로그래머는 최종 사용자가 프로그래머가 예상 한 값을 선택하지 않았다고 비난했습니다. 그런 다음 코드에서 while (true)의 모든 인스턴스를 제거했습니다.

IMHO while (true)와 같은 구문을 사용하는 것은 방어적인 프로그래밍이 아닙니다. 당신을 괴롭히기 위해 다시 올 것이다.

(그러나 i ++의 경우에도 모든 줄을 언급하지 않으면 교수들이 등급을 매기는 것을 기억합니다.)