2. 반복문 - for, while, do-while

반복문은 어떤 작업이 반복적으로 수행되도록 할 때 사용되며, 반복문의 종류로는 for문과 while문, do-while문이 있다. 
for문이나 while문에 속한 문장은 조건에 따라 한 번도 수행되지 않을 수 있지만 do-while문에 속한 문장은 최소한 한 번 이상 수행될 것을 보장한다. 
반복문은 주어진 조건을 만족하는 동안 주어진 문장들을 반복적으로 수행하므로 조건식을 포함하며 switch문을 제외한 if, for, while문에 사용되는 조건식은 연산결과가 반드시 boolean형, 즉 true 또는 false이어야 한다. 
[참고]C언어에서는 true와 false이외의 값도 허용한다. 

for문과 while문은 구조와 기능이 유사하여 어느 경우에나 서로 변환이 가능하기 때문에 반복문을 작성해야할 때 for문과 while문 중 어느 쪽을 선택해도 좋으나 for문은 주로 반복횟수를 알고 있을 때, 그리고 카운터가 반복문 내에 필요한 경우에 사용되고, 단순히 조건에 따른 반복만이 필요한 경우 while문을 사용하도록 한다. 

[참고]조건식을 잘못 작성하면, 한번도 수행되지 않거나 무한히 반복하게 되므로 주의해야한다. 



2.1 for문

for문의 기본구조는 다음과 같다. 


for (초기화;조건식;증감식) { 
      // 조건식의 연산결과가 true일 때 수행될 문장들을 적는다. 



[참고]반복하려는 문장이 단 하나일 때는 중괄호{}를 생략할 수 있다. 

초기화, 조건식, 증감식, 실행문과 같이 모두 4부분으로 이루어져 있으며, 실행순서는 아래와 같다. 

 

초기화는 처음에만 한번 수행되고, 그 이후부터는 조건식을 만족하는 한 2-3-4의 순서로 계속 반복된다. 조건식의 결과가 false가 되면, for문 전체를 빠져나가게 된다. 초기화, 조건식, 증감식은 모두 생략이 가능하며, 조건식이 생략되면 true로 간주된다. 


[표4-1]for문의 작성예 

[예제4-12] FlowEx12.java

class FlowEx12 

      public static void main(String[] args) 
      { 
            int sum =0;                   // 합계를 저장하기 위한 변수. 

            for(int i=1; i <= 10; i++) { 
                  sum += i ;             //       sum = sum + i; 
                  System.out.println( i + " 까지의 합: " + sum); 
            } 
      } 

[실행결과]
1 까지의 합: 1 
2 까지의 합: 3 
3 까지의 합: 6 
4 까지의 합: 10 
5 까지의 합: 15 
6 까지의 합: 21 
7 까지의 합: 28 
8 까지의 합: 36 
9 까지의 합: 45 
10 까지의 합: 55 

1부터 10까지의 합을 구하는 예제인데, 가장 일반적인 for문의 형태를 사용하고 있다. i가 1부터 10이 될 때까지(i가 10보다 같거나 작을 조건이 만족되는 동안), i를 1씩 증가시켜가면서 블럭{}내의 문장들을 반복 수행한다. 
sum +=i;는 sum = sum +i;를 줄여 쓴 것이며, sum에 저장되어 있는 값에 i의 값을 더해서 다시 sum에 저장한다.
이 수식은 i의 값의 변화에 따라 다음과 같이 계산된다. 

i가 1일 때 : 1 = 0 + 1       
i가 2일 때 : 3 = 1 + 2       
i가 3일 때 : 6 = 3 + 3       
      ... 
i가 10일 때 : 55 = 45 + 10       

[예제4-13] FlowEx13.java

class FlowEx13 

      public static void main(String[] args) 
      { 
            int sum =0;                   // 합계를 저장하기 위한 변수. 

            for (int i=1; i <= 10; i++) { 
                  sum += i ;             //       sum = sum + i; 
            } 
            System.out.println( i + " 까지의 합: " + sum);       // error발생!!! 
      } 


예제4-12를 변경한 것으로 최종 결과만을 출력하도록 하기 위해서 System.out.println( i + " 까지의 합: " + sum);을 for문 밖으로 빼낸 것이다. 별문제 없을 것처럼 보이지만, 컴파일시에 라인10에서 에러가 발생한다. 
그 이유는 변수 i를 for문의 초기화부분에서 선언을 했기 때문에 i가 유효한 영역은 오직 for문 내부 뿐인데, for문을 벗어난 곳에서 i를 사용했기 때문이다. 

[참고]for문 외에 다른 반복문이나 조건문에 선언된 변수들도 각 구문의 내부에서만 유효하다. 


원하는 결과를 얻기 위해서는 위의 예제를 다음과 같이 변경해야한다. 

[예제4-14] FlowEx14.java

class FlowEx14 

      public static void main(String[] args) 
      { 
            int sum =0;                   // 합계를 저장하기 위한 변수. 
            int i;                              // 선언부분을 for문 밖으로 옮겼다. 
            for(i=1; i <= 10; i++) { 
                    sum += i ;             //       sum = sum + i; 
            } 
           System.out.println( i-1 + " 까지의 합: " + sum); 
      } 

[실행결과]
10 까지의 합: 55 

변수 i를 for문 밖에서도 사용할 수 있도록, i의 선언부분을 for문 밖으로 빼내었다. i는 이제 main메서드 내에 선언된 변수이므로 for문 이후에도 유효하다. 
for문의 카운터로 사용되는 변수는 주로 for문의 블럭{} 내에서만 사용되기 때문에, for문 내에 선언해서 for문의 실행이 끝나고 나면 없어지도록 하는 것이 다음에 또 다른 반복문에서 다시 재사용할 수도 있어서 코드를 보다 단순화 하는데 도움이 된다. 

[예제4-15] FlowEx15.java

class FlowEx15 

      public static void main(String[] args) 
      { 
            int sum =0; 
            for(int i=0; i <=10; i+=2) { 
                  sum += i;             // sum = sum + i; 
                  System.out.println(i + " : " + sum); 
            } 
      } 

[실행결과]

0 : 0

2 : 2 
4 : 6 
6 : 12 
8 : 20 
10 : 30 


0과 10사이에 있는 짝수들의 합을 구하는 프로그램이다. for문의 증감식 부분에 카운터 i의 값을 2씩 증가시키기 위해 i+=2를 사용했다. 이처럼 카운터의 값을 원하는 만큼 값을 증가시키거나 감소시킬 수 있다. 증감식 부분 역시 for문의 초기화 부분처럼 쉽표(,)를 이용해서 여러 문장들을 넣을 수 있다. 

[예제4-16] FlowEx16.java

class FlowEx16 

      public static void main(String[] args) 
      { 
            for(int i=0, sum=0;i<10;System.out.println((i+=2)+ ":" + (sum+=i))); 
      } 


이전 예제의 for문을 한 줄로 작성해 보았다. 간략한 코드도 좋지만 이해하기 쉬운 코드가 더 좋은 코드이므로 별로 바람직하지는 않으니 참고만 하기 바란다. 

if문 내에 또 다른 if문을 넣을 수 있는 것처럼, 반복문 안에 또 다른 반복문을 포함시키는 것 역시 가능하다. 

[예제4-17] FlowEx17.java

class FlowEx17 

      public static void main(String[] args) 
      { 
            for(int i=2; i <=9; i++) { 
                  for(int j=1; j <=9; j++) { 
                        System.out.println( i +" * "+ j + " = " + i*j );                   
                  } 
            } 
      } 


반복문에 반복문을 사용해서 구구단을 출력하는 예제이다. i는 단을 출력하는 데 사용되며, j는 1부터 9까지의 곱에 사용된다. 2단부터 출력하기 위해 첫 번째 for문의 i는 2로 초기화 되었다. 

[예제4-18] FlowEx18.java

class FlowEx18 

      public static void main(String[] args) 
      { 
            for(int i=2; i <=9; i++) 
                  for(int j=1; j <=9; j++) 
                        System.out.println( i +" * "+ j + " = " + i*j );                   
      } 


구구단 예제를 보다 간단하게 바꾼 것이다. for문, while문, if문의 수행할 문장이 하나일 경우 중괄호{}를 생략할 수 있다. 두 번째 for문은 첫 번째 for문에 속한 한 문장으로, 출력문은 두 번째 for문에 속한 한 문장으로 간주된다. 
되도록이면 중괄호{}를 사용하는 것이 좋지만 너무 많아도 복잡하므로 경우에 따라서는 이처럼 간략하게 생략하는 것도 좋다. 

[예제4-19] FlowEx19.java

class FlowEx19 

      public static void main(String[] args) 
      { 
            long startTime = System.currentTimeMillis(); 
            for(int i=0; i < 1000000000; i++) { 
                  ; 
            } 
            long endTime = System.currentTimeMillis(); 

            System.out.println("시작시간 : " + startTime); 
            System.out.println("종료시간 : " + endTime); 
            System.out.println("소요시간 : " + (endTime - startTime)); 
      } 

[실행결과]
시작시간 : 1042517111350 
종료시간 : 1042517125520 
소요시간 : 14170 

currentTimeMillis()를 이용해서 for문의 이전과 이후의 시간을 얻은 다음 그 차이를 계산함으로써 for문을 수행하는데 걸린 시간을 측정하는 예제이다. 결과는 컴퓨터의 성능에 따라 다르며, 속도가 빠른 컴퓨터일수록 Start와 End간의 시간차가 적을 것이다. 
이 결과에서 알 수 있듯이 저자의 컴퓨터에서는 for문을 수행하는데 14.170초가 소요되었다. for문 내의 블럭{}에 아무런 작업도 하지 않는 빈 문장(;)만 들어있기 때문에, 조건식(i<1000000000)과 증감식(i++)만 10억 번을 반복해서 처리하는데 그 만큼의 시간이 걸린 것이다. 
이처럼 단순히 반복만 하는 for문을 사용하면 작업들 사이에 시간간격을 줄 수 있다. 
[참고]currentTimeMillis()는 1970년 1월 1일부터 현재까지의 시간을 천 분의 일초로 계산한 결과를 long형의 정수로 반환하는 메서드이다. 

[예제4-20] FlowEx20.java

class FlowEx20 

      public static void main(String[] args) 
      { 
            System.out.println("자, 이제 카운트 다운을 시작합니다."); 
            for(int i=10; i >= 0; i--) { 
                  for(int j = 0; j < 100000000; j++) { 
                        ; 
                  } 
                  System.out.println(i); 
            } 
            System.out.println("GAME OVER"); 
      } 

[실행결과]
자, 이제 카운트 다운을 시작합니다. 
10 










GAME OVER 

10부터 1까지 1씩 감소시켜가면서 출력을 하되 매출력마다 약 1초의 시간이 지연된다. 

위에 사용된 for문은 반복할 문장이 하나 밖에 없으므로 중괄호를 생략할 수 있으므로 다음과 같이 할 수 있다. 


for (int i=0; i < 1000000000; i++) ; 



예제에서는 for문의 중괄호{}내에 빈 문장(;)을 써주긴 했지만, 중괄호가 있을 때는 문장이 없어도 되므로 다음과 같이 쓸 수도 있다. 


for (int i=0; i < 1000000000; i++) {} 





2.2 while문

for문과는 달리, 조건식과 수행해야할 문장블럭{}만으로 구성되어 있지만 카운터로 사용할 변수와 증감식을 함께 사용함으로써 for문과 같이 구성할 수 있다. 그래서 for문과 while문은 항상 서로 대신 사용할 수 있다. 



while (조건식) { 
      // 조건식의 연산결과가 true일 때 수행될 문장들을 적는다. 




[예제4-21] FlowEx21.java

class FlowEx21 

      public static void main(String[] args) 
      { 
            int i=10; 
            while(i >=0) { 
                  System.out.println(i--); 
            } 
      } 

[실행결과]
10 











10부터 1씩 감소시켜가면서 출력하는 예제이다.출력문의 i--는 후위형이기 때문에 i가 출력된 후에 감소한다. 이와 같은 구조의 while문에서 주의할 점은 카운터로 사용되는 변수의 선언과 초기화 위치이다. 
만일 실수로 다음과 같이 i가 while문 내에 초기화된다면, 매 반복마다 i의 값이 10으로 초기화 되므로 while문은 무한 반복에 빠지게 된다. 


            int i = 0 ; 
            while (i >=0) { 
                  i=10 ; 
                  System.out.println(i--); 
            } 


그래서, 반복문에 카운터가 필요한 경우는 while문보다는 for문을 사용하는 것이 좋다. 

[예제4-22] FlowEx22.java

class FlowEx22 

      public static void main(String[] args) 
      {       
            int i=2; 
            while(i<=9) { 
                  int j=1; 
                  while(j <=9) { 
                        System.out.println( i +" * "+ j + " = " + i*j ); 
                        j++; 
                  } 
                  i++; 
            } 
      } 


while문을 사용해서 구구단을 출력하는 예제를 작성해보았다. for문으로 작성된 예제와 한번 비교해 보도록 하자. 

[예제4-23] FlowEx23.java

class FlowEx23 

      public static void main(String[] args) 
      { 
            int sum =0; 
            int i = 0; 

            while(sum + i <= 100) { 
                  sum += ++i;       // sum = sum + ++i; 
                  System.out.println(i + " - " + sum); 
            } 
      } 

[실행결과]
1 - 1 
2 - 3 
3 - 6 
4 - 10 
5 - 15 
6 - 21 
7 - 28 
8 - 36 
9 - 45 
10 - 55 
11 - 66 
12 - 78 
13 - 91 

1부터 몇까지 더하면 누적합계가 100에 가까워지는지 계산하는 예제이다. 



2.3 do-while문

while문의 변형으로 기본적인 구조는 while문과 같으나 블럭{}이 먼저 수행한 후에 조건식을 판단한다는 것이 while과의 유일한 차이점이다. 
while문은 조건식의 결과에 따라 블럭{}이 한번도 수행되지 않을 수 있지만, do-while문은 최소한 한번은 수행될 것을 보장한다. 



do { 
      // 조건식의 연산결과가 true일 때 수행될 문장들을 적는다. 
while (조건식); 


[예제4-24] FlowEx24.java

class FlowEx24 

      public static void main(String[] args) throws java.io.IOException 
      { 
            int input=0; 

            System.out.println("문장을 입력하세요."); 
            System.out.println("입력을 마치려면 x를 입력하세요."); 
            do { 
                  input = System.in.read(); 
                  System.out.print((char)input); 
            } while(input!=-1 && input !='x'); 
      } 

[실행결과]
C:\j2sdk1.4.1\work>java FlowEx24 
문장을 입력하세요. 
입력을 마치고 싶으면 x를 입력하세요. 
What do you want? 
What do you want? 
Tell me the truth. 
Tell me the truth. 


C:\j2sdk1.4.1\work> 

System.in.read()를 이용해서 화면을 통해 사용자로부터 입력을 받은 다음, 입력받은 내용을 다시 화면에 출력한다. 일단 사용자로부터 입력을 받은 후 입력받은 문자를 검사하므로 while문 보다는do-while문이 적합하다. 사용자가 'x'를 입력하거나 Ctrl+z를 입력하면 do-while문을 빠져나가 프로그램이 종료된다. 
System.in.read()는 사용자가 입력한 문자를 int형으로 반환하므로 문자가 아닌 문자의 코드값이 반환된다. 그래서 화면으로부터 입력받은 문자를 다시 출력하기 위해서는 char형으로 변환해야 한다. 
그리고 사용자가 입력한 문자가 Ctrl+z(키보드의 Ctrl키와 z키를 동시에 누름)이면 -1을 결과로 반환한다. 

[참고]OS가 윈도우인 경우에는 Ctrl+z이지만 유닉스에서는 Ctrl+d이며, 이는 파일의 끝(EOF)을 의미한다. 




2.4 break문

switch문에서 이미 배운 것과 같이 break문은 현재 위치에서 가장 가까운 switch문 또는 반복문을 벗어나는데 사용된다. 주로 if문과 함께 사용되어 특정 조건을 만족하면 반복문을 벗어나도록 한다. 

[실행결과]
i=15 
sum=105 

숫자를 1부터 계속 더해 나가서 몇까지 더하면 합이 100을 넘는지 알아내는 예제이다. i의 값을 1부터 1씩 계속 증가시켜가며 더해서 sum에 저장한다. sum의 값이 100을 넘으면 if문의 조건이 true이므로 break문이 수행되어 자신이 속한 반복문을 즉시 벗어난다. 
이처럼 무한 반복문에는 조건문과 break문이 항상 같이 사용된다. 그렇지 않으면 무한히 반복되기 때문에 프로그램이 종료되지 않을 것이다. 

[참고]sum += i;와 i++; 두 문장을 sum += i++;와 같이 한 문장으로 줄여 쓸 수도 있다. 



2.5 continue문

continue문은 반복문 내만 사용될 수 있으며, 반복이 진행 중에 continue문을 만나게 되면 반복문의 끝으로 이동하여 다음 반복으로 넘어간다. for문의 경우 증감식으로 이동하며, while문과 do-while문의 경우 조건식으로 이동한다. 
continue문은 반복문 전체를 벗어나지 않고 다음 반복을 계속 수행한다는 점이 break문과 다르다. 주로 if문과 함께 사용되어 특정 조건을 만족하는 경우에 continue문 이후의 문장들을 수행하지 않고 다음 반복으로 넘어가서 계속 진행하도록 한다. 전체 반복 중에 특정조건을 만족하는 경우를 제외하고자 할 때 유용하다.

[실행결과]






10 

1과 10사이의 숫자를 출력하되 그 중에서 3의 배수인 것은 제외하도록 하였다. 나머지 연산자를 사용해서 3으로 나눴을 때 나머지가 없으면 3의 배수이므로 이 경우 continue문이 실행되어 그 이후의 문장이 실행되지 않고 다음 반복으로 넘어간다. 



2.5 이름 붙은 반복문

여러 반복문이 중첩되어 있을 때 반복문 앞에 이름을 붙이고 break문과 continue문에 이름을 지정해 줌으로써 하나 이상의 반복문을 벗어나거나 반복을 건너뛸 수 있다. 

 
[실행결과]
2*1=2 
2*2=4 
2*3=6 
2*4=8 

구구단을 출력하는 예제이다. 제일 바깥에 있는 for문에 Loop1이라는 이름을 붙였다. 그리고 j가 5일 때 break문을 수행하도록 했다. 반복문의 이름이 지정되지 않은 break문은 자신이 속한 하나의 반복문만 벗어날 수 있지만, 지금처럼 반복문에 이름을 붙여 주고 break문에 반복문 이름을 지정해주면 하나 이상의 반복문도 벗어날 수 있다. 
j가 5일 때 반복문 Loop1을 벗어나도록 했으므로 2단의 4번째 줄까지 밖에 출력되지 않았다. 만일 반복문의 이름이 지정되지 않은 break문이었다면 2단부터 9단까지 모두 네 줄씩 출력되었을 것이다. 
3개의 주석처리된 break문과 continue문을 바꿔 가면서 어떤 결과를 얻을지 예측해보고 실행결과와 비교해 보도록 하자.


출처 - http://cafe.naver.com/javachobostudy


'Development > JavaEssential' 카테고리의 다른 글

java - 배열(Array)  (0) 2012.10.25
java - 연산자 2  (1) 2012.10.07
java - 변수  (0) 2012.09.24
String과 StringBuffer의 성능에 대해서...  (0) 2012.05.02
조건문  (0) 2012.04.19
Posted by linuxism
,