[자바 스터디] 4주차. 제어문 및 과제(JUnit,깃헙API,기초 자료구조)
10 Dec 2020
Reading time ~9 minutes
- 1. 선택문
- 2. 반복문
- 과제 0. JUnit 5 학습
- 과제 1. live-study 대시 보드 코드 작성
- 과제 2. LinkedList 구현
- 과제 3. Stack 구현
- 과제 4. ListNode를 사용한 Stack 구현
- 과제 5. Queue 구현
1. 선택문
1.1 if 문
자바의 if문은 아래 세 가지 형태 형태로 정의할 수 있습니다. 이때 Expression은 boolean 또는 Boolean 타입이여야 합니다. 그렇지 않은 경우 컴파일 타임 에러가 발생합니다. 또한 statement에는 BlockStatements도 포함됩니다. 그리고 여기서 statementNoShortIf란 IfThenStatement(Else가 없는 If문)를 제외한 모든 문장을 의미합니다.
-
1.1.1 IfThenStatement
if(Expression) Statement
-
1.1.2 IfThenElseStatement
if(Expression) StatementNoShortIf else Statement
-
1.1.3 IfThenElseStatementNoShortIf
if(Expression) StatementNoShortIf else StatementNoShortIf
-
1.1.4 If ElseIf Else Statement?
기존에 아래와 같이 if, else if, else를 사용한 문장을 본 적이 있습니다. 위에서는 if문의 형태는 3가지라고 하였는데 어떻게 된 걸까요?
if(Expression) Statement else if(Expression) Statement else Statement
자세히 말하자면 아래의 Statement 부분에 또 한번의 IfElseStatement가 중첩되어 나타난 것입니다. 그 아래 코드를 보면 위의 Statement 부분에 대괄호로 표시하여 IfElseStatement를 집어 넣어 보았습니다. 그렇게 하니 우리가 익히 알던 구문인 if, else if, else 구문이 나오는 것을 확인할 수 있습니다.
if(Expression) StatementNoShortIf else Statement
if(Expression) StatementNoShortIf else [if(Expression) StatementNoShortIf else Statement]
-
1.1.5 Example
점수 하나를 입력받아 점수에 따른 학점을 출력하는 예제를 작성해 보았습니다.
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.print("점수를 입력하세요:"); int score = sc.nextInt(); if(score >= 90) { if(score >= 97) { System.out.println("A+"); }else if(score >= 94){ System.out.println("A"); }else { System.out.println("A-"); } }else if(score >= 80){ System.out.println("B"); }else if(score >= 70) { System.out.println("C"); }else if(score >= 60) { System.out.println("D"); }else { System.out.println("F"); } sc.close(); } }
점수를 입력하세요:97 A+
-
1.1.6 Test
그럼 아래와 같은 코드는 무엇이 출력될까요?
int a = 1; int b = 1; if(a==0) if(b==0) System.out.println("if"); else System.out.println("else");
실행시켜 보면 아시겠지만 아무것도 출력되지 않습니다.
그럼 왜 그렇게 되는지 설명해 보겠습니다.
위에 구분된 것 처럼 if문은 3가지 형태(1.1.1 ~ 1.1.3)로 나누어 볼 수 있습니다. 또한 1.1.4의 코드에 나오는 조건문은 1.1.2나 1.1.3의 형태가 될 수 없습니다. 왜냐하면 두 형태 모두 statementNoShortIf가 와야 하기 때문에 그 자리에는 IfThenStatement(Else문이 없는 If문)를 사용할 수 없습니다.
따라서 아래 주석처리된 코드 처럼 동작하지 않습니다./* 주석 처리된 코드처럼 if else 문이 들여쓰기에 맞춰 동작하지 않습니다. if(a==0) if(b==0) System.out.println("if"); else System.out.println("else"); */
그래서 1.1.1의 형태에 statement 부분에 IfElseStatement가 들어간 것 처럼 주석처리되지 않은 코드처럼 동작하게 됩니다. 따라서 a가 0이 아닌 1이므로 if 문을 바로 벗어나기 때문에 아무것도 출력되지 않습니다.
// 들여쓰기와 관계없이 무조건 아래 처럼 동작합니다. if(a==0) if(b==0) System.out.println("if"); else System.out.println("else");
주석 처리된 동작을 하기 위해서는 중괄호 { } 를 넣어 BlockStatement로 바꾸어 주어야 합니다.
if(a==0) { if(b==0) System.out.println("if"); } else System.out.println("else");
1.2 switch 문
자바의 switch 문은 아래 세 가지 형태 형태로 정의할 수 있습니다. 이때 Expression은 char, byte, short, int, Character, Byte, Short, Integer, String, enum 타입 중 한가지여야 합니다. 그렇지 않은 경우 컴파일 타임 에러가 발생합니다. switch 문의 형태는 크게 다음 두 가지로 나누어 볼 수 있습니다.
-
1.2.1 Constant Type Expression
Switch 문의 Expression이 Constant 타입일 경우 입니다. ConstantExpression이란 primitive 타입과 String 타입의 리터럴 또는 그러한 타입으로 형변환 되는 것을 의미합니다.
switch(Expression){ case ConstantExpression : default : }
번호를 입력해 통신사를 선택하여 해당 통신사의 상담원과 전화 연결하는 상황을 가정하여 예제를 작성해 보았습니다.
public static void main(String[] args) { Scanner sc = new Scanner(System.in); System.out.println("1:SKT, 2:KT, 3:LG U+"); System.out.print("번호로 통신사를 선택해주세요 : "); int choice = sc.nextInt(); switch(choice) { case 1: System.out.println("SKT 상담원과 전화 연결해드리겠습니다."); break; case 2: System.out.println("KT 상담원과 전화 연결해드리겠습니다."); break; case 3: System.out.println("LG U+ 상담원과 전화 연결해드리겠습니다."); break; } }
1:SKT, 2:KT, 3:LG U+ 번호로 통신사를 선택해주세요 : 1 SKT 상담원과 연결하겠습니다.
-
1.2.2 Enum Type Expression
Switch 문의 Expression이 Enum 타입일 경우 입니다. Expression이 Enum 타입일 경우에는 switch문과 연결된 case 상수는 enum 타입 상수여야합니다.
switch(Expression){ case EnumConstantName : default : }
요일별 기분의 상태를 나타내는 예제를 작성해 보았습니다.
public class EnumSwitchTest { public enum Day { SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY } Day day; public EnumSwitchTest(Day day) { this.day = day; } public static void main(String[] args) { EnumSwitchTest enumTest = new EnumSwitchTest(Day.SATURDAY); enumTest.todayFeelling(); } public void todayFeelling() { switch (day) { case MONDAY: System.out.println("월요일은 Bad"); break; case FRIDAY: System.out.println("금요일은 Good"); break; case SATURDAY: case SUNDAY: System.out.println("주말에는 Happy"); break; default: System.out.println("주중에는 So So"); break; } } }
주말에는 Happy
2. 반복문
2.1 while 문
While 문은 다음과 같은 형태를 가지고 있습니다. 여기서 Expression은 boolean 또는 Boolean 타입이여야 합니다. Expression이 true이면 Statement를 실행합니다. Expression이 false 이면 더 이상 실행하지 않습니다.
while(Expression) {
Statement
}
2.2 Do 문
Do 문은 다음과 같은 형태를 가지고 있습니다. 여기서 Expression은 boolean 또는 Boolean 타입이여야 합니다. 우선 Statement를 실행하고 Expression이 true이면 다시 Statement를 실행합니다. Expression이 false 이면 더이상 실행하지 않습니다.
do Statement
while(Expression);
2.3 Basic For 문 (기본 For 문)
Basic For 문은 다음과 같은 형태를 가지고 있습니다.
for([ForInit];[Expression];[ForUpdate]) Statement
Expression은 boolean 또는 Boolean 타입이여야 합니다. Expression이 false가 될 때 까지 Statement, ForUpdate, Expression를 반복하여 실행합니다. 아래 숫자와 같은 순서로 반복하게 됩니다. 8번째 Expression이 false가 되는 경우에는 더 이상 실행하지 않고 for문 밖으로 나가게 되는 동작방식입니다.
for (① ForInit; ②⑤⑧ Expression; ④⑦ ForUpdate) {
③⑥ Statement
}
⑨
예를 들자면 i값이 0부터 9까지(10보다 작은 마지막 순간) 1씩 증가하면서 배열을 순회하며 배열의 합을 구하는 코드를 작성할 수 있습니다.
int sum = 0;
int arr [] = {1,2,3,4,5,6,7,8,9,10};
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
System.out.println("sum = " + sum);
sum = 55
만약 초기화를 실행한 직후 Expression이 false라면 어떻게 될까요?
int sum = 0;
int arr [] = {1,2,3,4,5,6,7,8,9,10};
for (int i = 10; i < arr.length; i++) {
System.out.println(i);
}
첫 번째로 ①초기화(ForInit)를 실행한 후 ②Expression이 false(10<10)가 되면 for문 밖으로 나가게 되어 어떠한 출력도 나오지 않는 것을 확인 할 수 있었습니다. Statement 부분에 작성했던 System.out.println(i); 문장이 단 한 번도 실행되지 않았습니다.
다음과 같이 forInit,Expression,forUpdate에 아무 것도 적지 않는다면 어떻게 될까요?
int i = 0;
for (;;) {
System.out.println(i);
}
0
0
0
.
.
.
이러한 문장도 실행이 가능합니다. println 문장을 무한히 실행하게 됩니다. for문의 종료조건이 없으므로 이러한 코드를 사용하면 안됩니다. 하지만 이처럼 forInit,Expression,forUpdate 중 일부 혹은 전체를 적지 않고도 코드 작성자에 재량에 따라 사용 가능하다는 사실을 확인 할 수 있었습니다.
2.4 Enhaned For 문 (향상된 For 문)
Enhanced For 문은 다음과 같은 형태를 가지고 있습니다.
for ( {VariableModifier} UnannType VariableDeclaratorId : Expression ) Statement
int sum = 0;
int arr [] = {1,2,3,4,5,6,7,8,9,10};
for (int i : arr) {
sum += i;
}
System.out.println("sum = " + sum);
sum = 55
Map<String, Integer> fruits = new HashMap<>();
fruits.put("apple",3);
fruits.put("banana",5);
fruits.put("orange",2);
for (Map.Entry<String, Integer> fruit : fruits.entrySet()) {
System.out.println(fruit.getKey() + ":" + fruit.getValue());
}
banana:5
orange:2
apple:3
2.5 break 문
break 문은 아래와 같은 형태를 가지고 있습니다. switch 문, while 문, do 문, for 문에서 주로 사용됩니다. Identifier와 함께 사용될 경우 Identiifier 밖으로 나가게 됩니다.
break [Identifier];
2.5.1 Identifier가 없을 경우
break가 속해있는 반복문 블록 외부로 나가게 됩니다. 예제의 경우 for문 밖으로 나가게 됩니다.
int sum = 0;
for (int i = 1; i <= 10; i++) {
sum += i;
if(i==5) {
System.out.println("i가 5이면 그만 실행");
break;
}
}
System.out.println("sum = " + sum);
i가 5이면 그만 실행
sum = 15
2.5.2 Identifier가 있을 경우
Identifier 외부로 나가게 됩니다.
public static void main(String[] args) {
Block:
{
int a = 0;
if(a==0) break Block;
System.out.println("블록 내부");
}
System.out.println("블록 외부");
}
블록 외부
a가 0이므로 Block 밖으로 나가게 되어 Block 외부라는 문자열만 출력됩니다.
구구단을 출력하되 3단을 제외하고 5단까지만 출력하도록 break 문을 사용해 보았습니다. 이 예제에서는 Identifier가 없다 하더라도 break가 속한 반복문을 벗어나는 동작은 동일합니다.
public class BreakTest {
public static void main(String[] args) {
IBlock:
for (int i = 2; i < 10; i++) {
JBlock:
for (int j = 1; j < 10; j++) {
if(i==3) break JBlock;
System.out.println(i + "*" + j + " = " + (i * j));
}
if(i==5) break IBlock;
}
}
}
2*1 = 2
2*2 = 4
2*3 = 6
2*4 = 8
2*5 = 10
2*6 = 12
2*7 = 14
2*8 = 16
2*9 = 18
4*1 = 4
4*2 = 8
4*3 = 12
4*4 = 16
4*5 = 20
4*6 = 24
4*7 = 28
4*8 = 32
4*9 = 36
5*1 = 5
5*2 = 10
5*3 = 15
5*4 = 20
5*5 = 25
5*6 = 30
5*7 = 35
5*8 = 40
5*9 = 45
다음 예제에서는 break에서 Identifier를 지우면 다른 결과가 나옵니다. 다만 JBlock안에 있는 break 문의 Identifier를 IBlock으로 고쳐보겠습니다.
public class BreakTest {
public static void main(String[] args) {
IBlock:
for (int i = 2; i < 10; i++) {
JBlock:
for (int j = 1; j < 10; j++) {
if(i==3) break IBlock; // 이 부분을 JBlock -> IBlock 으로 변경해 보았습니다.
System.out.println(i + "*" + j + " = " + (i * j));
}
if(i==5) break IBlock;
}
}
}
2*1 = 2
2*2 = 4
2*3 = 6
2*4 = 8
2*5 = 10
2*6 = 12
2*7 = 14
2*8 = 16
2*9 = 18
출력 결과가 2단까지만 나오는 것을 볼 수 있습니다. 이처럼 Identifier는 여러 개의 for문을 한 번에 break문으로 빠져나올 때 유용하게 사용할 수 있습니다.
2.6 continue 문
continue 문의 형태는 다음과 같습니다. break 문과 마찬가지로 Identifier와 함께 사용할 수 있습니다.
continue [Identifier];
1부터 10까지의 합을 구하돼 5일 때는 합을 구하지 않고 다음으로 스킵하겠다는 코드를 작성해 보았습니다.
int sum = 0;
for (int i = 1; i <= 10; i++) {
if(i==5) {
System.out.println("i가 5인 경우는 이후 동작을 Skip");
continue;
}
sum += i;
}
System.out.println(sum);
i가 5인 경우는 이후 동작을 Skip
50
1 ~ 10까지의 합인 55에서 5를 뺀 50이 결과값으로 출력됨을 확인할 수 있었습니다.
간단하게는 1부터 10까지의 홀수의 합을 구할 때 짝수는 continue를 이용해 Skip 하는 식으로 사용할 수 있습니다.
int sum = 0;
for (int i = 1; i <= 10; i++) {
if(i%2==0) continue; // i가 짝수인 경우는 이후 동작을 Skip
sum += i;
}
System.out.println("sum = " + sum);
sum = 25
break 문과 달리 다음 예제처럼 continue 문은 반복문 밖에서는 사용될 수 없습니다.
Block:
{
int a = 0;
if(a==0) continue Block;
System.out.println("블록 내부");
}
System.out.println("블록 외부");