Study/Java

[Java]연산자와 제어문

코챱 2022. 1. 11. 23:20

연산자

Java와 JavaScript는 비슷한 부분이 꽤 있어서, JS에서 다뤘던 연산자들이 Java에도 거의 똑같이 있다. 산술, 대입(복합 대입), 증감, 비교, 논리, 삼항 조건 연산자가 있다는 점은 같으면서 세부적으로 조금씩 다르긴 하다.

 

산술 연산자(+, -, *, /, %) 중 %가 나눗셈 결과에서 나머지를 뜻하는 건 JS와 같지만, Java에서 /는 나눗셈 결과 중 몫만을 말한다. 즉, 실수가 아니라 정수가 결과로 도출된다. 더불어 Java의 산술 연산 시에는 자동 형 변환이 일어나기 때문에, int 이하의 타입들은 int로, 그 외에는 큰 타입 쪽으로 변환된다.

대입 연산자(=)와 복합 대입 연산자(+=, -=, *=, /=, %=)는 우변 값을 좌변에 계산하여 대입한다는 의미로, JS에서와 같다. 그리고 이 복합 대입 연산자(확장 연산자)에서는 자동 형 변환이 일어나지 않는다.

또한 증감 연산자(++, --)도 JS와 같이 전위 연산(선행 연산)과 후위 연산(후행 연산)이 있다.

비교 연산자는 JS와 약간 다른데, JS에서는 ===와 !==가 있었지만 Java에서는 없다. 단순히 ==와 !=가 equal과 not equal을 뜻한다. 비교 연산 시 피연산자의 타입이 서로 다르면 큰 타입 쪽으로 일치시킨 후 연산을 수행하고, 보통은 그냥 되지만 float와 double의 경우 유효 자릿수의 차이로 비교 결과가 제대로 나오지 않는다.

그리고 논리 연산자(&&, ||, !, ^) 중에는 JS에서 나오지 않은 ^가 있다. 똑같이 &&는 and, ||는 or, !는 not을 뜻하며, ^는 피연산자가 서로 다를 때 true, 같을 때 false를 도출하는 연산자다.

마지막으로 삼항 조건 연산자는 역시 "조건식 ? 실행문1 : 실행문2;" 의 형태로 수행되는데, 사실 중첩하여 쓸 수 있다. "조건식1 ? 실행문1 : 조건식2 ? 실행문2 : 실행문3;" 형식으로 쓰게 되면 조건식1이 거짓일 때 조건식2가 수행되서, 조건식2가 참일 경우 실행문2, 거짓일 경우 실행문3이 도출된다.

int a = 10/3;   //나눗셈 결과 중 몫(결과 3 도출)

byte b = 1, c = 2;   //byte 타입 변수 b와 c
System.out.println(b+c);   //int 타입으로 변환, 3 출력

short s = 3;
a += s;   //좌변 short 타입 s를 우변 int 타입 a에 더함, 자동 형 변환 불가능, 결과 6 도출

a++;   //후위연산
--a;   //전위연산

float f = 0.1f;
double d = 0.1;
System.out.println(f == d);   //유효자릿수 문제로 false 출력

3 ^ 4;   //결과 true 도출

b<c ? c : b>a ? b : a;   //중첩 삼항 조건 연산

 

추가적으로 연산자의 우선순위 역시 JS와 비슷하며, 좀 더 자세히 나눠보면

1. ( )

# 1)단항  2)이항  3)삼항

# 1)산술  2)비교  3)논리  4) 대입, 복합 대입

으로 구분할 수 있다. 우선순위가 같을 경우에는 왼쪽에서부터 연산을 수행하면 되지만 대입 연산자는 예외다.

 

제어문

제어문도 역시 JS에서처럼 조건문, 선택문, 반복문, 보조제어문이 있다. JS와 똑같이 if ~ else if ~ else문(조건문), switch-case문(선택문)과 for문, while문, do ~ while문(반복문), 그리고 break문, continue문(보조제어문)으로 나뉜다. 물론 사용 방법도 똑같다.

여기서 조건문 사용 시 주의할 점이 있다. if문과 else if문, else문 뒤에 실행코드가 한 문장이라면 { }(중괄호)를 생략 가능한데, 잘못 생략했을 때 Dangling Else 문제가 일어난다. Dangling Else 문제란 if와 else가 짝을 이루는 규칙에 대해, 중괄호가 없을 경우에는 else문이 바로 위에 가장 가까운 if문에 붙게 되는 현상을 말한다. 그래서 원래의 결과가 아닌 다른 값이 도출될 수 있기 때문에, 웬만하면 { }를 생략하지 않는 것이 좋다.

//Dangling Else
int i = 10, j = 20;

if(i > j)
	if(j > 5)
		System.out.println(i);
else
	if(j > 5)
		System.out.println(j);
        
System.out.println("Done");

위의 코드에서 else는 첫 번째 if문과 연결되는 것으로 쓴 것이다. 하지만 중괄호가 없기 때문에, 컴퓨터는 이 else를 바로 위의 두 번째 if문과 연결되는 것으로 읽는다. 그래서 원래 출력되어야 할 j 가 아니라 Done이 출력된다.

 

조건문과 선택문은 둘 다 조건에 부합하는 코드를 실행하는 것이라 비슷한 경우에 쓰일 수 있다. 하지만 선택문인 switch-case문은 연산자를 사용할 수 없어서 사용 방식이 약간 다르다. 아래는 성적 확인 프로그램을 조건문(if ~ else if ~ else문)으로 작성한 것이다. 비교, 논리 연산자를 사용하여 점수를 10점 단위로 구분하고 60점 미만은 F로 설정했다.

int score = 87;

if(90 <= score && score <= 100) {
	System.out.println(score + "점의 학점 : A";
}
else if(80 <= score && score < 90) {
	System.out.println(score + "점의 학점 : B";
}
else if(70 <= score && score < 80) {
	System.out.println(score + "점의 학점 : C";
}
else if(60 <= score && score < 70) {
	System.out.println(score + "점의 학점 : D";
}
else {
	System.out.println(score + "점의 학점 : F");
}

 

그리고 아래는 똑같은 문제를 선택문(switch-case문)으로 작성한 것이다. 선택문은 변수 형태로 설정해야 가능하기 때문에, 10점 단위로 학점이 구분되는 것을 이용했다. switch-case문을 쓸 때는 항상 break문을 써 줘야 한다.

int score = 87;

switch(score /= 10) {
case 10:
case 9:
	System.out.println(score + "점의 학점 : A"); break;
case 8:
	System.out.println(score + "점의 학점 : B"); break;
case 7:
	System.out.println(score + "점의 학점 : C"); break;
case 6:
	System.out.println(score + "점의 학점 : D"); break;
default :
	System.out.println(score + "점의 학점 : F");
}

 

다음으로 반복문인 for문과 while문, do ~ while문도 JS에서와 같은 방법으로 사용한다. do ~ while문은 거의 쓰지 않아서, for문과 while문만 예시를 적었다.

아래는 for문으로 별 그리기 코드와 피보나치수열 코드를 작성한 것이다. 별 그리기는 별 1개로 시작하여 계단처럼 각 줄에 하나씩 추가하는 형태고, 피보나치수열은 1, 1로 시작해서 앞의 두 숫자를 더해가며 값을 나열하는 것이다.

//별 그리기
for(int i=1; i<=5; i++) {
	for(int j=1; j<=i; j++) {
		System.out.println("*");    //5줄 짜리 계단식 별 모양 출력
	}
System.out.println();
}


//피보나치 수열
int i = 1; j = 1;
int sum = 0;

System.out.println(i);
System.out.println(j);

for(int num=3; num<=11; num++) {    //11번째 피보나치 수 까지
	sum = i+j;
	i = j;
	j = sum;
    
	System.out.println(sum);    //1 1 2 3 5 8 13 21 34 55 89 출력
}

 

그리고 아래는 while문으로 누적합과 각 자리 정수의 합을 구하는 코드다. 누적합은 1에서 n까지 정수를 모두 더해 출력하는 코드이며, 각 자리 정수의 합을 구하는 것은, 예를 들어 123 입력 시 1+2+3의 값을 출력하는 코드다.

//누적합
int i = 1;
int sum = 0;

while(i <= 10) {
	sum += i;
	i++;
}
System.out.println(sum);   //1~10까지 정수의 총합인 55 출력


//각 자리 정수의 합
int j = 123456;
int total = 0;

while(j > 0) {
	total += (j%10);
	j /= 10;
}
System.out.println(total);   //1+2+3+4+5+6 인 21 출력

 

이제 마지막으로 다중 for문 구구단 코드를 작성하여, 안쪽 for문에 보조제어문을 사용했다.

for(int dan=2; dan<10; dan++) {
	for(int i=1; i<10; i++) {
        if(i == 5) {
		break;    //dan * i 에서 i가 5일 때 break
	}
	System.out.println(dan + " * " + i + " = " + dan*i);
}

위처럼 break문을 작성하면 2단부터 9단까지 다 출력되지만, 모두 dan * 1부터 dan * 4 까지만 존재하고 5부터는 나오지 않는다. 똑같은 코드에서 break를 continue로 바꿨을 경우에는, 모든 값이 출력되고 dan * 5 줄만 제외된다.

참고로 break문은 조건문과 결합하여 많이 사용된다.