코린이의 소소한 공부노트

제어문 (1) 조건문 - if, else if, else 본문

Java

제어문 (1) 조건문 - if, else if, else

무지맘 2022. 1. 4. 23:16

조건문이란 조건을 만족할 때만 해당 블록을 실행시키는 제어문이다.

  - 조건이 참일 경우 해당 블록 1번 실행

  - 조건이 거짓일 경우 해당 블록 실행 안 함

 

if문의 기본 생김새는 이렇다.

if (조건식1) {
	// 조건식1이 참이면
	// 이 블록 실행
}
else if (조건식2) {
	// 조건식1은 거짓이면서
	// 조건식2가 참이면
	// 이 블록 실행
}
else {
	// 조건식1, 2 모두 거짓이면
	// 이 블록 실행
}

1. if

  - 조건식이 참일 때만 실행된다.

  - 조건식이 거짓이면 해당 if 블록을 빠져나온다.

  - if는 필요한 만큼 중첩해서 사용이 가능하다.

  - else가 없어도 된다.

  - else가 있을 경우, if의 조건식이 거짓일 때 else 블록이 실행된다.

문자열을 비교하는 메서드 2가지를 비교해보자.

String str = "Hi";

if (str.equalsIgnoreCase("hi"))
	System.out.println("같은 문장. 대소문자 무시");

if (str.equals("hi"))
	System.out.println("같은 문장. 대소문자 구분");
else
	System.out.println("다른 문장. 대소문자 구분");

// "같은 문장. 대소문자 무시"
// "다른 문장. 대소문자 구분"

equalsIgnoreCase()는 대소문자를 무시하고 같은 문자열인지 비교하는 메서드이다."Hi"나 "hi"나 같은 알파벳으로 구성된 문자열이므로 조건이 참이 되어  if 블록을 실행시킨다.

equals()는 완벽히 똑같은 문자열인지 비교하는 메서드이다. "Hi"는 "hi"와 같은 알파벳이지만 H가 대문자인 것이 다르기 때문에 조건이 거짓이 되어 else 블록을 실행시킨다.

2. else if

  - if와 함께 쓰이며, if의 조건이 거짓일 때 else if의 조건식을 계산하게 된다.

  - else if의 조건식이 참이면 해당 else if의 블록을 실행한다.

  - else if의 조건식이 거짓이면 해당 else if 블록을 빠져나온다.

  - 한 if문에 else if는 여러 개 나와도 된다.

점수에 따라 등급을 나눠보는 if문을 만들어보았다.

int score = 70;
char grade = ' ';

if (score >= 90) {         // score가 90 이상이면 
	 grade = 'A';
} else if (score >=80) {   // score가 80 이상이면 B
	 grade = 'B';
} else if (score >=70) {   // score가 70 이상이면 C
	 grade = 'C';
} else {                   // 나머지는 D
	 grade = 'D'; 
}
System.out.println("등급: " + grade);

굉장히 보편적인 기준으로 등급을 나눠보았다. 등급이 C로 정해지는 과정은 다음과 같다.

  - 70은 90보다 작기 때문에 if의 조건식이 거짓이 되어 첫 번째 else if로 넘어갔다.

  - 70은 80보다 작기 때문에 else if의 조건식이 거짓이 되어 두 번째 else if로 넘어갔다.

  - 70은 70 이상이므로 else if의 조건식이 참이 되어 grade = 'C';가 실행되었다.

위 if문은 else if를 사용하지 않고도 표현이 가능하다.

if (score >= 90)               // score가 90 이상이면 
	 grade = 'A';
if (80 <= score && score < 90) // score가 80 이상 90 미만이면 B
	 grade = 'B';
if (70 <= score && score < 80) // score가 70 이상 80 미만이면 C
	 grade = 'C';
if (score < 70)                // score가 70 미만이면 D
	grade = 'D'
System.out.println("등급: " + grade);

else if는 if의 조건식이 거짓일 때 실행되기 때문에 else if를 if로 바꿀 때 조건식에 if 조건식의 반대 조건이 추가로 붙었다. 어떻게 보면 등급을 나누는 기준이 확실하여 보여서 이게 더 좋아 보일 수 있다. 하지만 이게 최선일까..?

3. else

  - if문의 가장 마지막 부분에 오는 블록이다.

  - else문 위의 모든 조건이 거짓일 때 실행된다.

  - 생략 가능하다.

  - 가장 가까운 if문과 짝을 이룬다.

중첩 if문으로 예를 들어 보겠다.

int num = -1;

if (num >= 0)
	if (num > 0)
		System.out.println("양수");
else
	System.out.println("음수");
    
// 아무 것도 출력되지 않았다.
// ??

들여 쓰기를 보면 맨 처음 if문에서 -1 >= 0이 거짓이기 때문에 else문으로 가야 할 것 같지만, else는 가장 가까운 if문과 짝을 이루기 때문에 두 번째 if문의 else로 들어가게 된다. 즉, 실제로는 아래와 같은 상황이었다는 것이다.

if (num >= 0){
	if (num > 0)
		System.out.println("양수");
	else
		System.out.println("음수");
}

첫 if문이 참이고 두 번째 if문이 거짓일 때 실행되는 else문이 되기 때문에, num이 -1일 때 실행될 일이 없는 것이다. 이것을 우리가 의도한 대로 수정하려면 아래 코드처럼 블록 처리를 확실히 해줘야 한다.

if (num >= 0){
	if (num > 0)
		System.out.println("양수");
    }
else
	System.out.println("음수");

 

if문은 위에서 잠깐 언급했듯이 필요한 만큼 중첩 사용이 가능하다. 중첩 사용은 if 블록 안에 또 다른 if 블록을 넣을 수 있다는 것을 말한다.

정수 num이 30의 배수인지 확인하는 if문을 만들어보았다. 30 = 2 * 3 * 5이므로 2, 3, 5의 배수인지 확인해보면 된다.

if(num%2 == 0)
	if(num%3 == 0)
		if(num%5 == 0)
			System.out.println("30의 배수입니다.");

num에 60이 저장되어있다고 가정해보자.

  - 60은 2의 배수이므로 첫 번째 조건식은 참이다.

  - 60은 3의 배수이므로 두 번째 조건식도 참이다.

  - 60은 5의 배수이므로 세 번째 조건식도 참이다. 그래서 아래 println()이 실행된다.

위 if문은 중첩을 하지 않아도 표현 가능하다.

if(num%2 == 0 && num%3 == 0 && num%5 == 0)
	System.out.println("30의 배수입니다.");

if 조건이 모두 참이어야 중첩된 if문 안의 내용을 실행할 수 있기 때문에 AND 연산으로 이어진 1개의 if문으로도 표현이 가능하다. 하지만 이게 최선일까..?


[쿠키글] 코드를 간결하게 바꿔보기 - refactoring

리팩터링이란 결과는 변하지 않고 내부 논리나 구조등을 유지보수를 하는 행위를 일컫는다. 프로그래밍에서의 리팩터링은 같은 결과를 내면서 코드를 더 간결하게 바꾸는 작업을 말한다.

위에서 '하지만 이게 최선일까?'라고 했던 이유는, 과연 이 코드들이 리팩토링이 가능한지, 혹은 리팩터링이 된 것인지 의문점이 생겼기 때문이다. 지금부터 위의 코드들을 다시 한번 보면서 리팩터링을 해보겠다.

 

1. 여러 개 중 한 개만 실행시키고 싶을 때는  if - else if

  - 각 조건들이 교집합이 없을 경우, else if를 사용하는 것이 좋다.

int score = 70;
char grade = ' ';
if (score >= 90)               // score가 90 이상이면 
	 grade = 'A';
if (80 <= score && score < 90) // score가 80 이상 90 미만이면 B
	 grade = 'B';
if (70 <= score && score < 80) // score가 70 이상 80 미만이면 C
	 grade = 'C';
if (score < 70)                // score가 70 미만이면 D
	grade = 'D'
System.out.println("등급: " + grade);

score값이 조건식을 참으로 만드는 식을 만나려면 5번의 비교 연산, 2번의 논리 연산을 거쳐야 한다.

int score = 70;
char grade = 'D'; // 조건식이 모두 거짓일 때

if (score >= 90) {         // score가 90 이상이면 
	 grade = 'A';
} else if (score >=80) {   // score가 80 이상이면 B
	 grade = 'B';
} else if (score >=70) {   // score가 70 이상이면 C
	 grade = 'C';
}
System.out.println("등급: " + grade);

else if를 이용했을 때, score값이 조건식을 참으로 만드는 식을 만나려면 3번의 비교 연산만 하면 된다. 이에 덧붙여 초기값을 'D'로 설정해 else문을 생략할 수도 있다.

 

2. 각각의 조건식이 참이냐 거짓이냐에 따라 실행되는 것이 다 다른 경우 - 중첩 if

  - 각 조건들의 교집합이 있을 경우, 중첩 if로 나타내는 것이 좋다.

위에서 봤던 30의 배수 찾기에서 if를 하나만 쓴 코드를 가지고와봤다.

if(num%2 == 0 && num%3 == 0 && num%5 == 0)
	System.out.println("30의 배수입니다.");

2의 배수, 3의 배수, 5의 배수를 다 만족할 때만 30의 배수라는 문구가 출력됐는데, 이것을 좀 더 세분화해보면...

if(num%2 == 0 && num%3 == 0 && num%5 == 0)
	System.out.println("2, 3, 5의 배수입니다.");
if(num%2 == 0 && num%3 == 0 && num%5 != 0)
	System.out.println("2, 3의 배수입니다.");
if(num%2 == 0 && num%3 != 0 && num%5 == 0)
	System.out.println("2, 5의 배수입니다.");
// ...

num값이 10이었다면 총 9번의 비교 연산과 6번의 논리연산을 해야 출력 결과를 볼 수 있다. 몹쓸 짓이다. 중첩 if를 써서 그나마 낫게 표현해보자면 3번의 비교 연산만 하면 된다.

if(num%2 == 0) {
	if(num%3 == 0) {
		if(num%5 == 0)
			System.out.println("2, 3, 5의 배수");
		else
			System.out.println("2, 3의 배수");
		}
	else {
		if(num%5 == 0)
			System.out.println("2, 5의 배수");
		else
			System.out.println("2의 배수");
	}
}

else {
	if(num%3 == 0) {
		if(num%5 == 0)
			System.out.println("3, 5의 배수");
		else
			System.out.println("3의 배수");
		}
	else {
		if(num%5 == 0)
			System.out.println("5의 배수");
		else
			System.out.println("2, 3, 5의 배수 아님");
	}
}

들여 쓰기로 가독성을 올리긴 했으나, 경우의 수가 8가지나 되다 보니 복잡한 감이 있다. 더 줄일 수 있는 방법이 생각나면 수정하겠다.

'Java' 카테고리의 다른 글

제어문 (2) 반복문 - for  (0) 2022.01.07
제어문 (1) 조건문 - switch  (0) 2022.01.05
제어문과 블록, 특별한 키워드  (0) 2022.01.03
조건 연산과 대입 연산  (0) 2022.01.01
비교 연산과 논리 연산  (0) 2021.12.31