반복문과 조건문
- 프로그래밍 언어/자바
- 2020. 11. 29. 19:45
프로그래밍에서 중요하다고 할 수 있는 반복문과 조건문에 대해 학습할 것이다.
반복문
자바에서 기본 반복문으로 3가지가 존재한다,
for, while , do- while
3가지의 공통점은 반복을 시킨다는 것입니다. 그런데 어째서 반복문을 3가지로 구분 지었을까요?
1. for
for(int i = 0; i< 10;i++) {
}
for문은 초기화, 범위, 증감값을 작성할 수 있다.
여기서 한가지 이상을 생략할 수 있는데 생략하는 방법은 작성하지 않는 것이다.
그렇다면 for문은 언제 작성할까?
이글을 읽오보면 for문은 반복문의 숫자가 고정될때 사용한다고 합니다.그러니까 배열값을 순회할때 index값이 필요할 경우 for문을 사용하면 더 좋을 것 같다는 뜻입니다.
{
public For();
descriptor: ()V
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 1: 0
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=1
0: iconst_0
1: istore_1
2: iload_1
3: bipush 10
5: if_icmpge 14
8: iinc 1, 1
11: goto 2
14: return
LineNumberTable:
line 4: 0
line 6: 14
StackMapTable: number_of_entries = 2
frame_type = 252 /* append */
offset_delta = 2
locals = [ int ]
frame_type = 250 /* chop */
offset_delta = 11
}
2. while
while(조건문) {
}
while문은 for문에 비해 간결한것 같다. 하지만 변수가 설정되어 있지 않는다. 만약, 변수를 사용하고 싶다면, 맴버 변수에 정의를 해두어야 사용이 가능하다. 그러면 간결해지는게 아니라 오히려 더러워지는게 아닐까?
아니면 애초에 사용하는 곳?이 다른 걸까?
이 글에 따르자면 while문은 고정되지 않는 값?에서 사용한다고 한다.
링크드 리스트라는 자료구조가 존재한다. 링크드 리스트의 가장 큰 특징은 다음에 값이 있는지 없는지 있는지 알 수 있다.
다음에 값이 존재 할때까지 반복문을 반복 시켜주면 된다.
{
public While();
descriptor: ()V
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 1: 0
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=1
0: iconst_0
1: istore_1
2: iload_1
3: bipush 10
5: if_icmpge 14
8: iinc 1, 1
11: goto 2
14: return
LineNumberTable:
line 3: 0
line 4: 2
line 5: 8
line 7: 14
StackMapTable: number_of_entries = 2
frame_type = 252 /* append */
offset_delta = 2
locals = [ int ]
frame_type = 11 /* same */
}
SourceFile: "While.java"
3.do-while
do-while은 지금까지 놔왔던 반복문과 약간의 차이가 존재한다.
가장 큰 차이점은 반복을 하기전에 한번 실행하고 반복을 한다는 점이다. 마치 a++가 유사한 느낌이 든다.
do {
} while(조건문);
do에서 일단 실행하구 반복문을 돌린다.
{
public DoWhile();
descriptor: ()V
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 1: 0
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=1
0: iconst_0
1: istore_1
2: iinc 1, 1
5: iload_1
6: bipush 10
8: if_icmplt 2
11: return
LineNumberTable:
line 3: 0
line 5: 2
line 6: 5
line 7: 11
StackMapTable: number_of_entries = 1
frame_type = 252 /* append */
offset_delta = 2
locals = [ int ]
}
그러면 do-while문은 어디에 사용될까? while문과 유사하지만 무조건 실행을 먼저 시켜야되는 경우에 사용하는것이 좋을 것 같다.
지금까지 반복문의 종류에 대해 살펴 봤다. 조금더 반복문에 대해 이해 해보자.
4. while vs do while
while문과 do while문의 바이트 코드를 읽어 보면
while문은 1,2,3,5,8이지만 do-while문은 1,2,5,6,8이 이 부분이 다르다.
그렇다면 왜 이런 차이를 보일까?
두개 모두 변수를 100으로 두고 그 범위를 넘어서는 순간 hello를 출력하는 코드를 작성해보자.
private static void getDoWhile() {
int i = 100;
do {
System.out.println("doWhile : hello");
} while (i < 100);
}
private static void getWhile() {
int i = 100;
while(i < 100) {
System.out.println("while: hello");
}
}
출력을 보시면 dowhile문만 출력 되는 것을 확인 할 수 있다. 코드를 보면 i가 100이기 때문에 조건에 만족하지 않는다. 그럼에도 do-while문은 동작하였다. 왜냐하면 do-while문은 print문부터 동작하는것에 비해 while문은 조건에 만족하지 않으므로 아무것도 출력 되지 않았다.
5. 반복문은 왜 사용하는가?
지금까지 기본 반복문에 대해 알아보았다. 그런데 이들은 왜 사용할까?
반복문은 말 그대로 반복하기 위한 문법이다. 그렇다면 반복문을 사용하지 않고 1부터 10까지 출력하는 print를 작성한다고 가정하자.
그러면 다음과 같이 작성해야한다.
System.out.println(1);
System.out.println(2);
System.out.println(3);
System.out.println(4);
System.out.println(5);
System.out.println(6);
System.out.println(7);
System.out.println(8);
System.out.println(9);
System.out.println(10);
이렇게 작성해야한다. 1부터 10까지라 작성하기 쉬웠지만 1부터 10억까지 출력한다고 한다면.... 이것도 일일이 타이핑을 해야할까?
바이트 코드를 살펴보자.
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
3: iconst_1
4: invokevirtual #13 // Method java/io/PrintStream.println:(I)V
7: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
10: iconst_2
11: invokevirtual #13 // Method java/io/PrintStream.println:(I)V
14: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
17: iconst_3
18: invokevirtual #13 // Method java/io/PrintStream.println:(I)V
21: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
24: iconst_4
25: invokevirtual #13 // Method java/io/PrintStream.println:(I)V
28: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
31: iconst_5
32: invokevirtual #13 // Method java/io/PrintStream.println:(I)V
35: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
38: bipush 6
40: invokevirtual #13 // Method java/io/PrintStream.println:(I)V
43: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
46: bipush 7
48: invokevirtual #13 // Method java/io/PrintStream.println:(I)V
51: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
54: bipush 8
56: invokevirtual #13 // Method java/io/PrintStream.println:(I)V
59: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
62: bipush 9
64: invokevirtual #13 // Method java/io/PrintStream.println:(I)V
67: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
70: bipush 10
72: invokevirtual #13 // Method java/io/PrintStream.println:(I)V
75: return
LineNumberTable:
line 3: 0
line 4: 7
line 5: 14
line 6: 21
line 7: 28
line 8: 35
line 9: 43
line 10: 51
line 11: 59
line 12: 67
line 13: 75
}
바이트 코드도 끔찍하다.
이것을 어떻게 하면 반복문으로 만들 수 있을까?
반복문의 가장 중요한 요소는 조건식이다. 왜냐하면 조건식에 의해 반복문이 동작하기 때문이다.
그러면 어떤 조건이 필요할까? 1부터 10까지 순차적으로 증가하고 있다. 또, 모두 10이하다.
그렇기 때문에 10이하로 작성하면 될까?
기본 조건문에는 for,while,do-while문이 존재한다. 이들중에 어떤것으로 작성해야 유리할까?
바로 for문이다. 왜냐하면 초기값, 조건식, 증감값 모두 알고 있기 때문이다. 다른것으로 작성이 불가능한것은 아니지만 for문이 가장 편하기 때문에 for문을 선택하였다.
for(int i = 1;i<=10;i++) {
System.out.println(i);
}
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=1
0: iconst_1
1: istore_1
2: iload_1
3: bipush 10
5: if_icmpgt 21
8: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
11: iload_1
12: invokevirtual #13 // Method java/io/PrintStream.println:(I)V
15: iinc 1, 1
18: goto 2
21: return
LineNumberTable:
line 3: 0
line 4: 8
line 3: 15
line 6: 21
StackMapTable: number_of_entries = 2
frame_type = 252 /* append */
offset_delta = 2
locals = [ int ]
frame_type = 250 /* chop */
offset_delta = 18
}
놀랍게도 바이트코드 또한 줄었다는것을 확인 되었다.
이로써 사람의 관점이나 기계의 관점이나 반복문을 사용하는게 더 유리하는 것이 증명되었다.
6. 확장된 for문
for-each문이라고 불리며
for문의 장점과 while문의 장점을 잘 결합시킨듯한 모습을 가지고 있다.
생김새는 for문과 유사하지만 while문과 같이 간결한 모습을 보여준다.
for(변수 : 배열) {
}
이 반복문은 위 처럼 작성한다. while문에서는 만약, 조건에 만족하는 다음 값이 존재한다면 반복문을 동작시킨다. 이 점이 while문과의 유사성이다. 하지만, while보다는 for문에 더 가까워보인다. 굳이 비율로 따지면 1 : 9정도?
for문에서는 index조작이 가능했지만, 확장된 for문에서는 불가능하다. 대부분 이 방식은 배열에서 사용이 된는데, index조작이 필요없을 때 위 방법을 선택한다. 따지고 보면 배열의 맨처음 부터 끝까지 동작하게 되는 것이 된다.
이 방식은 굉장히 유용하지만, 배열에서만 사용이 가능하다는 점에 유의해야한다.
다음과 같은 배열이 있다고 가정하자. 일반적인 for문에서는 index 0번부터 동작하게 된다. 그리고 마지막 9까지 동작을 한뒤 종료가 된다.
향상된 for문도 같은 동작을 한다. 암묵적으로 index 0번 부터 끝까지 동작하게 되는 것이 향상된 for문의 특징이다.
정리하자면, 배열과 같은 연속된 자료형에서만 사용할 수 있으며 처음부터 끝까지 순회를 한다.
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=3, args_size=1
0: bipush 10
2: newarray int
4: astore_1
5: iconst_0
6: istore_2
7: iload_2
8: aload_1
9: arraylength
10: if_icmpge 23
13: aload_1
14: iload_2
15: iload_2
16: iastore
17: iinc 2, 1
20: goto 7
23: iconst_0
24: istore_2
25: iload_2
26: aload_1
27: arraylength
28: if_icmpge 44
31: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
34: iload_2
35: invokevirtual #13 // Method java/io/PrintStream.println:(I)V
38: iinc 2, 1
41: goto 25
44: return
LineNumberTable:
line 3: 0
line 4: 5
line 5: 13
line 4: 17
line 8: 23
line 9: 31
line 8: 38
line 11: 44
StackMapTable: number_of_entries = 4
frame_type = 253 /* append */
offset_delta = 7
locals = [ class "[I", int ]
frame_type = 250 /* chop */
offset_delta = 15
frame_type = 252 /* append */
offset_delta = 1
locals = [ int ]
frame_type = 250 /* chop */
offset_delta = 18
}
for문
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=6, args_size=1
0: bipush 10
2: newarray int
4: astore_1
5: iconst_0
6: istore_2
7: iload_2
8: aload_1
9: arraylength
10: if_icmpge 23
13: aload_1
14: iload_2
15: iload_2
16: iastore
17: iinc 2, 1
20: goto 7
23: aload_1
24: astore_2
25: aload_2
26: arraylength
27: istore_3
28: iconst_0
29: istore 4
31: iload 4
33: iload_3
34: if_icmpge 57
37: aload_2
38: iload 4
40: iaload
41: istore 5
43: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
46: iload 5
48: invokevirtual #13 // Method java/io/PrintStream.println:(I)V
51: iinc 4, 1
54: goto 31
57: return
LineNumberTable:
line 3: 0
line 4: 5
line 5: 13
line 4: 17
line 8: 23
line 9: 43
line 8: 51
line 11: 57
StackMapTable: number_of_entries = 4
frame_type = 253 /* append */
offset_delta = 7
locals = [ class "[I", int ]
frame_type = 250 /* chop */
offset_delta = 15
frame_type = 254 /* append */
offset_delta = 7
locals = [ class "[I", int, int ]
frame_type = 248 /* chop */
offset_delta = 25
}
두개를 비교해보자.
향상된 for문이 훨씬 바이트가 많이 필요하다는 것을 알 수 있었다.
그러면 속도는 어떨까?
1000개의 데이터를 넣고 돌려본 결과
일반 for은 14 가 걸린거에 비해 for-each는 4정도의 시간이 걸렸다. 이로써 for-each의 속도가 조금더 빠르다는 것을 알 수 있다. 인터넷을 찾아본 결과 linkedList에서는 일반 for가 더 빠르다고 한다.
for each 시간 차이 : 14
for 시간 차이 : 4
조건문
조건문은 조건식을 이용해서 프로그래밍을 제어하는 문법이다. 대표적으로 if와 switch가 있다.
1. if , if-else , else
가장 단순한 조건문으로
if (조건식) {
} else if (조건식) {
} else {
}
이런식으로 작성된다.
보통은 반복문과 사용이 되며, 반복문을 제어할때 사용한다. 왜냐하면 조건문을 단독으로 사용할 경우 의미가 없기 때문이다.(메소드나 함수로 만들때는 제외된다.)
예를들어 1부터 10까지 출력하는 반복문에서 짝수만 구한다고 가정하자.
for(int i = 0; i<10;i++) {
if (i % 2 == 0) {
System.out.println(i);
}
}
그럼 이렇게 작성된다. 그러면 else if 와 else는 무엇일까?
이것을 한글화? 시키자면..
만약에(조건) {
} 만약에 그렇지 않는다면(조건) {
} 그렇지도 않는다면 {
}
라고 동작하게 된다. 그런데... 한가지 의문이 생긴다.
if if 와 if else if는 다르게 동작할까?
if(조건식) {
} else if (조건식) {
}
=================
if (조건식) {
}
if (조건식) {
}
이 두가지의 동작은 같을까? 다를까?
결과만 말하자면 다르게 동작한다. 이유가 무엇일까?
애초에 else if는 if의 조건식에 만족해야 동작하므로, 만족하지 않는다면 동작하지 않는다.
for(int i = 0; i<10;i++) {
if (i % 2 == 0) {
System.out.println(i);
} else if (i%3==0) {
System.out.println(i);
}
}
어떻게 나올까? 결과는 0,2, 3,4,8,9가 나오게 된다.하지만
public static void main(String[] args) {
for(int i = 0; i<10;i++) {
if (i % 2 == 0) {
System.out.println(i);
}
if (i%3==0) {
System.out.println(i);
}
}
}
경우는 0,0,2,3,4,6,6,8,9가 나오게 된다. 왜 이런 현상이 발생할까? 6를 예로 들어보자 6은 2의 배수이자 3의배수다.
그렇기때문에 두 개의 조건식에 만족하게 된다. 그래서 2번 출력이 되는 것도 그 이유다.
그러면 if else를 사용하는게 좋을까? 혹자는 if else 나 else사용하지 말고 코딩해보라고 권유한다.
어떻게 해야 중복된게 없이 출력할 수 있을까? 이 내용은 추후에 작성할 예정이다.
2. switch
switch문은 마치 if문을 대량으로? 사용하는 듯한 느낌을 받는 조건문이다.
swhich(변수) {
값 1 :
실행문;
break;
값 2 :
실행문;
break;
값 3 :
실행문;
break;
값 4 :
실행문;
break;
값 5 :
실행문;
break;
default :
실행문;
break;
}
사용법은 다음처럼 사용된다.
if와 비교하면 첫번째 case는 if와 매칭이 되고, 나머지는 if else와 default는 else와 매칭이 된다.
JDK7이전에는 변수 부분에 정수만 넣을 수 있었지만, 그 이후에는 다른 변수도 넣을 수 있다고 합니다.
3.continue와 break
continue와 break는 반복문내에서 조건문을 제어하기 위한 문법이다.
예를들어 1부터 10까지 작성하는 프로그램을 작성한다고 가정하자.
for(int i = 0;i<=10;i++) {
}
여기서 이렇게 작성하면 어떻게 될까?
for(int i = 0;i<=10;i++) {
if ( i == 6) {
break;
}
}
i가 5보다 커지면 이 프로그램(for문)이 종료 된다는 뜻이다.
즉, 0,1,2,3,4,5 가 출력 된다는 뜻이 된다.
이것을 바이트 코드로 열어서 확인하자.
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=1
0: iconst_0
1: istore_1
2: iload_1
3: bipush 10
5: if_icmpgt 30
8: iload_1
9: bipush 6
11: if_icmpne 17
14: goto 30
17: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
20: iload_1
21: invokevirtual #13 // Method java/io/PrintStream.println:(I)V
24: iinc 1, 1
27: goto 2public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=1
0: iconst_0
1: istore_1
2: iload_1
3: bipush 10
5: if_icmpgt 30
8: iload_1
9: bipush 6
11: if_icmpne 17
14: goto 30
17: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
20: iload_1
21: invokevirtual #13 // Method java/io/PrintStream.println:(I)V
24: iinc 1, 1
27: goto 2
30: return
LineNumberTable:
line 3: 0
line 4: 8
line 5: 14
line 7: 17
line 3: 24
line 9: 30
StackMapTable: number_of_entries = 3
frame_type = 252 /* append */
offset_delta = 2
locals = [ int ]
frame_type = 14 /* same */
frame_type = 250 /* chop */
offset_delta = 12
}
30: return
LineNumberTable:
line 3: 0
line 4: 8
line 5: 14
line 7: 17
line 3: 24
line 9: 30
StackMapTable: number_of_entries = 3
frame_type = 252 /* append */
offset_delta = 2
locals = [ int ]
frame_type = 14 /* same */
frame_type = 250 /* chop */
offset_delta = 12
}
자 이제 continue에 대해 살펴보자.
for(int i = 0;i<=10;i++) {
if ( i == 6) {
continue;
}
}
이건 0,1,2,3,4,5,7,8,9,10이 나온다. 뭔가 이상하다. 마치 break는 종료같고, continue는 무시 같은 느낌이 든다,
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=1
0: iconst_0
1: istore_1
2: iload_1
3: bipush 10
5: if_icmpgt 30
8: iload_1
9: bipush 6
11: if_icmpne 17
14: goto 24
17: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
20: iload_1
21: invokevirtual #13 // Method java/io/PrintStream.println:(I)V
24: iinc 1, 1
27: goto 2
30: return
LineNumberTable:
line 3: 0
line 4: 8
line 5: 14
line 7: 17
line 3: 24
line 9: 30
StackMapTable: number_of_entries = 4
frame_type = 252 /* append */
offset_delta = 2
locals = [ int ]
frame_type = 14 /* same */
frame_type = 6 /* same */
frame_type = 250 /* chop */
offset_delta = 5
}
위에서 if else 나 else사용하지 말고 코딩하라고 권유하라고 하였다. 그 이유는 가독성도 이유지만 continue와 break를 이해하는데 이만한게 없다고 생각하기 때문이다.
public static void main(String[] args) {
for(int i = 0; i<10;i++) {
if (i % 2 == 0) {
System.out.println(i);
continue;
}
if (i%3==0) {
System.out.println(i);
continue;
}
}
}
이렇게 작성하게 되면 2의 배수를 만족하는 순간 다시 반복문으로 가게 되고 그렇지 않는다면 3의 배수 조건식으로 가게 된다.
추가적으로 이들을 어떻게 하면 더 나눌수 있을까 에대해 고민하는것도 좋다고 생각한다.
'프로그래밍 언어 > 자바' 카테고리의 다른 글
Live-Study 대시 보드 만들기. (0) | 2020.12.06 |
---|---|
Junit5 (0) | 2020.12.04 |
백기선님 스터디에서 배운거 2가지 (간략히 정리) (0) | 2020.11.29 |
연산자 (0) | 2020.11.26 |
자바 데이터 타입, 변수 그리고 배열 (5) | 2020.11.18 |