코드 실행 흐름을 개발자가 원하는 방향으로 바꿀 수 있도록 해주는 것을 흐름 제어문이라고 한다.
제어문은 조건식과 중괄호 { } 블록으로 구성되는데, 조건식의 연산 결과에 따라 블록 내부의 실행 여부가 결정된다.
제어문의 종류는 다음과 같다.
조건문 | 반복문 |
---|---|
if 문, switch 문 | for 문, while 문, do-while 문 |
if 문은 조건식의 결과에 따라 블록 실행 여부가 결정된다.
다음은 if 문의 실행 흐름을 보여준다.
예제는 다음과 같다.
if (조건식) {
실행문;
실행문;
}
실행문이 하나라면 중괄호를 생략할 수 있다.
if (조건식)
실행문;
위 경우에는 if 문과 실행문을 같은 행에 작성하는 것이 일반적이다.
if (조건식) 실행문;
이것이 자바다 교재에서는 실행문이 하나인 경우에도 중괄호를 생략하지 않는 것을 권장하고 있다.
if 문과 실행문을 같은 행에 작성하지 않는 경우 다음과 같은 실수가 발생할 수 있는 것은 사실이다.
if (조건식)
실행문;
실행문; // if문과는 전혀 관계가 없는 실행문
하지만 if 문과 실행문을 같은 행에 작성한다면 코드의 가독성을 높이는 동시에 무의미하게 코드 라인이 늘어나는 것을 방지할 수 있다.
// 중괄호 생략
if (조건식) 실행문;
if (조건식) 실행문;
if (조건식) 실행문;
// 중괄호 사용
if (조건식) {
실행문;
}
if (조건식) {
실행문;
}
if (조건식) {
실행문;
}
또한 Mono Project Coding Guidelines와 GNU Coding Standards에서도 not to use curly braces if it's not necessary
, 즉 중괄호가 필수적이지 않은 상황에서는 사용하지 않을 것을 권장하고 있다.
코딩 스타일에 정답은 없지만 중괄호 생략 여부는 개인 취향의 문제인 것 같다.
동일한 실행문을 반복적으로 실행해야 할 경우에는 반복문을 사용한다. for문에 대해 알아보자.
다음은 for 문의 실행 흐름을 도식화한 것이다.
for 문이 처음 실행될 때 1
초기화식이 제일 먼저 실행된다.
그런 다음 2
조건식을 평가해서 true이면 3
실ㅇ문을 실행시키고, false이면 for 문을 종료하고 블록을 건너뛴다.
2
조건식이 true가 되어 다시 true이면 3
-> 4
-> 2
로 다시 진행하고, false이면 for문이 끝나게 된다.
다음은 가장 기본적인 for문의 형태로 1부터 10까지 출력하는 코드이다.
package ch04.sec04;
public class PrintFrom1To10Example {
public static void main(String[] args) {
for(int i=1; i<=10; i++) {
System.out.print(i + " ");
}
}
}
for 문을 사용할 때 주의점은 초기화식에서 부동 소수점을 쓰는 float 타입을 사용하지 말아야 한다는 것이다.
다음 예시를 보자. 이론적으로 5행의 for 문은 10번 반복해야 한다.
package ch04.sec04;
public class FloatCounterExample {
public static void main(String[] args) {
for(float x=0.1f; x<=1.0f; x+=0.1f) {
System.out.println(x);
}
}
}
하지만 부동 소수점 방식의 float 타입은 연산 과정에서 정확히 0.1을 표현하지 못하기 때문에 증감식에서 x에 더해지는 실제 값은 0.1의 근사값이다. 따라서 최종 반복 횟수는 10번이 아닐 수 있다.
위 코드를 실제로 동작시켜보면 9번 반복하는 것을 알 수 있다.
for 문이 정해진 횟수만큼 반복한다면, while 문은 조건식이 true일 경우에 계속해서 반복하고, false가 되면 종료한다.
다음은 while 문의 실제 흐름을 보여준다.
while 문이 처음 실행될 때 1
조건식을 평가한다. 평가 결과가 true이면 2
실행문을 실행한다. 2
실행문이 모두 실행되면 조건식으로 되돌아가서 1
조건식을 다시 평가한다. 다시 조건식이 true라면 2
->1
로 진행하고, false라면 while문을 종료한다.
다음은 while 문으로 1부터 10까지 출력하는 예제이다.
package ch04.sec05;
public class PrintFrom1To10Example {
public static void main(String[] args) {
int i = 1;
while (i<=10) {
System.out.print(i + " ");
i++;
}
}
}
경우에 따라서는 블록 내부를 먼저 실행시키고, 실행 결과에 따라서 반복 실행을 계속할지 결정하는 경우도 있다. 이때 do-while 문을 사용한다.
다음은 do-while 문의 실행 흐름을 보여준다.
작성 시 주의할 점은 while() 뒤에 반드시 세미콜론(;)을 붙여아 한다는 점이다.
do-while 문이 처음 실행될 때 1
실행문을 우선 실행한다.
1
실행문이 모두 실행되면 2
조건식을 평가하는데, 그 결과가 true이면 1
->2
와같이 반복 실행을 하고, 조건식의 결과가 false이면 do-while 문을 종료한다.
다음은 키보드로 입력받은 내용을 조사하여 계속 반복할 것인지를 판단하는 예제이다.
package ch04.sec06;
import java.util.Scanner;
public class DoWhileExample {
public static void main(String[] args) {
System.out.println("메시지를 입력하세요.");
System.out.println("프로그램을 종료하려면 q를 입력하세요.");
Scanner scanner = new Scanner(System.in);
String inputString;
do {
System.out.print(">");
inputString = scanner.nextLine();
System.out.println(inputString);
} while( ! inputString.equals("q") );
System.out.println();
System.out.println("프로그램 종료");
}
}
do-while 문의 존재는 알고 있었지만 실제로 개발을 하면서 막상 사용할 일은 거의 없는 것 같다.
내가 작성한 코드 뿐 만 아니라 오픈 소스 프로젝트를 봐도 do-while 문이 사용 되는 곳은 거의 없는 것 같다.
break 문은 for, while, do-while 문의 실행을 중지하거나 조건문인 switch 문을 종료할 때 사용한다.
다음은 반복문에서 break 문을 사용할 때의 실행 흐름을 보여준다.
다음 예제는 while 문을 사용해 주사위 번호 중 하나를 반복적으로 뽑되, 6이 나오면 while 문을 종료하는 예제이다.
package ch04.sec07;
public class BreakExample {
public static void main(String[] args) throws Exception {
while(true) {
int num = (int)(Math.random()*6) + 1;
System.out.println(num);
if(num == 6) {
break;
}
}
System.out.println("프로그램 종료");
}
}
여기 까지는 C언어와 같은 기존의 C-Like 언어들과 동일하지만 자바에는 특별한 기능이 더 있다.
만약 반복문이 중첩되어 있을 경우 break 문은 가장 가까운 반복문만 종료하는데, 중첩된 반복문에서 바깥쪽 반복문까지 종료시킬 수 있는 레이블
기능이 있다.
아래 예제를 보면 바깥쪽 for 문은 'A'~'Z'까지 반복하고, 중첩된 for 문은 'a'~'z'까지 반복한다.
중첩된 for 문에서 lower 변수가 'g'를 갖게 되면 바깥쪽 for 문까지 빠져나오도록 바깥쪽 for 문에 Outter 라는 라벨을 붙였다.
package ch04.sec07;
public class BreakOutterExample {
public static void main(String[] args) throws Exception {
Outter: for(char upper='A'; upper<='Z'; upper++) {
for(char lower='a'; lower<='z'; lower++) {
System.out.println(upper + "-" + lower);
if(lower=='g') {
break Outter;
}
}
}
System.out.println("프로그램 실행 종료");
}
}
continue 문은 반복문인 for, while, do-while 문에서만 사용되며 for 문의 증감식 또는 while, do-while 문의 조건식으로 바로 이동하는 역할을 한다.
다음은 continue 문의 실행 흐름을 보여준다.
다음 에제에서는 1에서 10 사이의 수 중에서 짝수만 출력하고 홀수인 경우에는 다음 반복으로 넘어간다.
package ch04.sec08;
public class ContinueExample {
public static void main(String[] args) throws Exception {
for(int i=1; i<=10; i++) {
if(i%2 != 0) {
continue;
}
System.out.print(i + " ");
}
}
}
지금까지 if
, for
, while
, do-while
, break
, continue
문을 다뤘다.
break
문의 Label
기능을 제외하면 위 6개 구문은 C언어와 같은 기존의 C-Like 언어들과 동일하다.
switch 문은 변수의 값에 따라서 실행문이 결정되기 때문에 같은 기능의 if 문 보다 코드가 간결해진다.
다음은 switch 문의 실행 흐름을 도식화한 것이다.
switch 문은 괄호 안의 변수값에 따라 해당 case로 가서 실행문을 실행시킨다.
만약 변수값과 동일한 값을 갖는 case가 없으면 default로 가서 실행문을 실행시킨다.
default가 필요 없다면 생략 가능하다.
package ch04.sec03;
public class SwitchExample {
public static void main(String[] args) {
int num = (int)(Math.random()*6) + 1;
switch(num) {
case 1:
System.out.println("1번이 나왔습니다.");
break;
case 2:
System.out.println("2번이 나왔습니다.");
break;
case 3:
System.out.println("3번이 나왔습니다.");
break;
case 4:
System.out.println("4번이 나왔습니다.");
break;
case 5:
System.out.println("5번이 나왔습니다.");
break;
default:
System.out.println("6번이 나왔습니다.");
}
}
}
switch 문의 괄호에는 정수 타입(byte
, char
, short
, int
, long
)과 문자열 타입(String
) 변수를 사용할 수 있다.
여기까지는 기존의 C-Like 언어들과 동일하지만 Java 12 이후부터 사용 가능한 Switch Expression 문에 대해 알아보자.
Switch Expression 문은 break 문을 없애는 대신에 화살표와 중괄호를 사용해 가독성이 좋아졌다.
아래 예제를 보자.
package ch04.sec03;
public class SwitchExpressionsExample {
public static void main(String[] args) {
char grade = 'B';
switch(grade) {
case 'A', 'a' -> {
System.out.println("우수 회원입니다.");
}
case 'B', 'b' -> {
System.out.println("일반 회원입니다.");
}
default -> {
System.out.println("손님입니다.");
}
}
switch(grade) {
case 'A', 'a' -> System.out.println("우수 회원입니다.");
case 'B', 'b' -> System.out.println("일반 회원입니다.");
default -> System.out.println("손님입니다.");
}
}
}
중괄호 안에 실행문이 하나만 있는 경우에는 if 문과 동일하게 중괄호를 생략할 수 있다.
Switch Expression을 사용하면 스위치된 값을 변수에 바로 대입할 수도 있다.
단일 값일 경우에는 화살표 오른쪽에 값을 기술하면 되고,
중괄호를 사용할 경우에는 yield
(Java13 부터 사용 가능) 키워드로 값을 지정하면 된다.
단, 이 경우에는 default
가 반드시 존재해야 한다.
다음은 grade에 따라 스위치된 점수를 score 변수에 대입하는 예제이다.
package ch04.sec03;
public class SwitchValueExample {
public static void main(String[] args) {
String grade = "B";
//Java 11 이전 문법
int score1 = 0;
switch(grade) {
case "A":
score1 = 100;
break;
case "B":
int result = 100 - 20;
score1 = result;
break;
default:
score1 = 60;
}
System.out.println("score1: " + score1);
//Java 12부터 가능
int score2 = switch(grade) {
case "A" -> 100;
case "B" -> {
int result = 100 - 20;
//Java 13부터 가능
yield result;
}
default -> 60;
};
System.out.println("score2: " + score2);
}
}