기초단계/JAVA

2022.11.15-1 JAVA 연산자

춘핑이 2022. 11. 15. 19:00

3. 연산자

3.1 부호 증감 연산자

부호 연산자는 부호를 유지하거나 변경
+ 피연산자 피연산자의 부호유지
-피연산자 피연산자의 부호 변경

int x = -100;
x = -x;
System.out.println("x: " + x); //100

byte b = 100;
int y = -b;
System.out.println("y: " + y); //-100

증감연산자 ++ -- ++피연산자 --피연산자 피연산자의 값을 1증가, 감소
피연산자++ 피연산자-- 다른 연산을 수행한 후에 피연산자 값을 증가,감소

int x = 1;
int y = 2;
int result1 = ++x +10; // int result1 = 2 + 10
int result2 = y++ + 10; // int result2 = 1+10 ->  y를 1증가

int x = 10;
int y = 10;
int z;

x++;
++x;
System.out.println("x= "+x);
System.out.println("--------------------");
y--;
--y;
System.out.println("y= "+y);
System.out.println("--------------------");
z= x++;
System.out.println("z= "+z);
System.out.println("x= "+x);
System.out.println("--------------------");
z = ++x;
System.out.println("z= "+z);
System.out.println("x= "+x);
System.out.println("--------------------");
z = ++x + y++;
System.out.println("z= "+z);
System.out.println("x= "+x);
System.out.println("y= "+y);

3.2 산술연산자

+덧셈연산 -뺄셈연산 *곱셈연산 /나눗셈연산 %나눗셈과 나머지
피연산자가 정수타입(byte short char int)면 연산결과는 int타입
피연산자가 정수탕비이고 그 중하나가 long타입이면 연산결과 long타입
피연산자중 하나가 실수타입 이면 결과는 실수타입

byte v1 = 10;
byte v2 = 4;
int v3 = 5;
long v4 = 10L;

int result1 = v1 + v2; //모든 피연산자는 int타입으로 자동변환 후 연산
System.out.println("result1 :" + result1);

long result2 = v1 + v2 - v4; // 모든 피연산자는 long타입으로 자동변환 후 연산
System.out.println("result2 :" + result2);

double result3 = (double) v1 / v2; //double타입으로 강제 변환 후 연산
System.out.println("result3 :" + result3);

int result4 = v1 % v2;
System.out.println("result4 :" + result4);

3.3 오버플로우와 언더 플로우

오버플로우란 타입이 허용하는 최댓값을 벗어나는 것 반대로 언더플로우는 타입이 허용하는 최솟값을 벗어나는 것.
벗어나면 오류가 발생하는게 아니라 최솟값 또는 최댓값으로 되돌아감.
오버플로우와 언더플로우는 기대값이 아니ㅡ므로 범위를 항상 주의할것 int가 넘을거 같으면 long으로쓰기
하나라도 long && 마지막값 long -> long연산되기 위해

byte value = 127;
value++; //value값에 1을 더함 128이아니라 최솟값으로 가버림
System.out.println(value); //-128

byte var1 = 125;
for(int i=0; i<5; i++)
{
    var1++;
    System.out.println("var1: " + var1);
}
System.out.println("------------------");
byte var2 = -125;
for(int i=0; i<5; i++)
{
    var2--;
    System.out.println("var2: " + var2);
}

3.4 정확한 계산은 정수 연산으로

산술연살을 정확하게 하고 시팓면 실수타입을 사용하지 앟는것이 좋다.
사과1개를 0.1단위의 10조각 그중 7조각(0.7)을 뺀 3조각 0.3을 result에 저장

int apple = 1;
double pieceUnit = 0.1;
int number = 7;

double result = apple - number*pieceUnit;
System.out.println("사과1개에서 남은양:" + result);
//사과1개에서 남은양:0.29999999999999993 0.3이 안나옴 부동소수점방식을 사용하는 실수타입에서 흔히 일어남 정확한 계산을         위해서라면 정수연산하자

int apple2 = 1;
int totalPieces = apple * 10;
int number2 = 7;

int result2 = totalPieces - number2;
System.out.println("10조각에서 남은 조각:" + result2);
System.out.println("사과1개에서 남은양:" + result2/10.0);

3.5 나눗셈 연산후 NaN과 Infinity 처리

나눗셈 || 나머지 연산에서 우측 피연산자가 정수 0일경우 예외(ArithmeticException)이 발생한다.
무한대값을 정수로 표현할수 없기때문이다.
그렇기때문에 /와 %연산의 결과가 infinity || nan인지 확인할 필요가 있다.
boolean result = Double.isInfinite(변수);
boolean result = Double.isNaN(변수);

int x = 5;
double y = 0.0;
double z = x / y;
//double z = x % y;

//잘못된 코드
System.out.println(z + 2);
//System.out.println(z + 2);

//알맞은 코드
if(Double.isInfinite(z) || Double.isNaN(z))
{
    System.out.println("값 산출 불가");
}
else
{
    System.out.println(z + 2);
}

3.6 비교연산자

동등비교 ==같은지 검사 !=다른지 검사
크기비교 > >= < <=
피연산자의 타입이 다를경우 연산을 수행하기 전에 타입을 일치시킨다.
'A' == 65 -> 65 == 65 -> true
한가지 예외 0.1f == 0.1 에서 0.1f 가 0.1이 되지않음. 부동 소수점 방식을 사용하는 실수 타입은 0.1을 정확히 표현할 수 없고 double타입과 정밀도 차이로인해 비교불가
0.1f == (float) 0.1로 비교해야함.
문자열 비교할때는 euqals() 와 !equals()를 사용 5장에서 자세히
boolean result = str1.equals(str2); //문자열이 같은지 검사(대소문자 구분)
boolean result = ! str1.equals(str2); //문자열이 다른지 검사

int num1 = 10;
int num2 = 10;
boolean result1 = (num1 == num2);
boolean result2 = (num1 != num2);
boolean result3 = (num1 <= num2);
System.out.println("result1: " + result1);
System.out.println("result2: " + result2);
System.out.println("result3: " + result3);

char char1 = 'A';
char char2 = 'B';
boolean result4 = (char1 <= char2); // 65 < 66
System.out.println("result4: " + result4);

int num3 = 1;
double num4 = 1.0;
boolean result5 = (num3 == num4);
System.out.println("result5: " + result5);

float num5 = 0.1f;
double num6 = 0.1;
boolean result6 = (num5 == num6);
boolean result7 = (num5 == (float) num6);
System.out.println("result6: " + result6);
System.out.println("result7: " + result7);

String str1 = "자바";
String str2 = "JAVA";
boolean result8 = str1.equals(str2);
boolean result9 = ! str1.equals(str2);
System.out.println("result8: " + result8);
System.out.println("result9: " + result9);

3.7 논리연산자

AND(논리곱) &&또는& 피연산자가 모두 참일경우만 true
OR(논리합) ||또는| 피연산자 중 하나만 참인경우 true
XOR(배타적논리합) ^ 피연산자가 하난는 true이고 다른하나가 false일 경우만 true
NOT(논리부정) ! 피연산자의 논리값을 바꿈 !true = false !false = true
&&와 &의 차이 &&는 앞의 피연산자가 false라면 뒤를 평가하지 않고 false를 바로 산출 but &는 두 피연산자 모두를 평가한 후 결과를 냄 따라서 &&가 더효율적임

int charCode = 'A';
//int charCode = "a";
//int charCode = '5';

if( (65<=charCode) & (charCode<=90))
{
    System.out.println("대문자이군요.");
}
if( (97<=charCode) && (charCode<=122))
{
    System.out.println("소문자이군요.");
}
if( (48<=charCode) && (charCode<=57))
{
    System.out.println("0~9 숫자이군요");
}  

3.8 비트 논리 연산자

it단위로 논리 연산 수행 0과 1 이 피연산자가 되므로 2진수 0과 1 로 저장되는정수타입(byte, short, int, long)만 가능
피연산자가 1,0 산출결과가 1,0 1은 true 0은 false라고 보면된다.
AND(논리곱) & 두 비트 모두 1일경우에만 연산결과가 1
OR(논리합) | 두비트 중 하나만 1이면 연산결과가 1
XOR(배타적 논리합) ^ 두 비트 중 하나는 1이고 다른하나가 0일경우 연산결과가 1
NOT(논리부정) ~1 = 0 / ~0=1 보수

45 & 25 2진수
00101101 =45
00011001 =25
00001001 = 9

비트 논리연산이 필요한이유?
비트단위로 계산을 해야할때(데이터 크기 측정) 웹개발에서는 거의 사용되지 않으니 이해만 하기.
소형 임베디드 장치c프로그램에서 외부 서버 자바 프로그램으로 데이터를 전달할때 c언어에는 uint_t타입이 있는데
이 타입은 1byte크기를 가지면서 0~255값의 범위를 가진다.
c프로그램이 unit8_t타입 136을 2진수로 보내면 자바는 2 진수를 -120으로 읽게된다. 자바는 최상위 비트가 1이면 음수로 인식하기때문
-120을 복원하고 싶다면 -120 & 255를 수행하면됨.
255와 비트 논리곱 연산을 수행하는 방법도 있지만 자바느 개발자의 편리성을 위해 Byte.toUnsignedInt()코드를 제공한다.

System.out.println("45& 25 = " + (45 & 25));
System.out.println("45| 25 = " + (45 | 25));
System.out.println("45^ 25 = " + (45 ^ 25));
System.out.println("~45 = " + (~45));
System.out.println("--------------------");
byte receiveData = -128;

//방법1 : 비트 논리곱 연산으로 Unsigned 정수 얻기
int unsignedInt1 = receiveData & 255;
System.out.println(unsignedInt1);

int unsignedInt2 = Byte.toUnsignedInt(receiveData);
System.out.println(unsignedInt2);

int test = 136;
byte btest = (byte) test;
System.out.println(btest);

3.9 비트 이동 연산자

비트 이동연산자는 비트를 좌측 또는 우측으로 밀어서 이동시키는 연산을 수행한다.
a << b 정수a의 각 비트를 b만큼 왼쪽으로 이동 오른쪽 빈자리는 0으로 채움 a x 2^b와 동일한결과
a >> b 정수a의 각 비트를 b만큼 오른쪽으로 이동 왼쪽 빈자리는 최상위 부호 비트와 같은값으로 채움. a/2^b와 같은 결과
a>>>b 정수a의 각 비트를 b만큼 오른쪽으로 이동 왼쪽 빈자리는 0으로 채움

int result = 1 << 3; 0001 -> 1000 => 1 x 2^3 = 8
int result = -8 >> 3;
최상위비트(=맨앞 양수0 음수1)
11111111 11111111 11111111 11111000
ㅁㅁㅁ1111 11111111 11111111 11111111 왼쪽빈자리는 최상위비트로 채움
11111111 11111111 11111111 11111111 = -1

int num1 = 1;
int result1 = num1 << 3;
int result2 = num1 * (int) Math.pow(2, 3); 
// Math.pow(2, 3)는 2^3을 연산하고 double로 산출 int값 보려면 (int)로 강제변환 필요

System.out.println("result1: " + result1);
System.out.println("result2: " + result2);

int num2 = -8;
int result3 = num2 >> 3;
int result4 = num2 / (int) Math.pow(2, 3); 
// Math.pow(2, 3)는 2^3을 연산하고 double로 산출 int값 보려면 (int)로 강제변환 필요

System.out.println("result3: " + result3);
System.out.println("result4: " + result4);

3.10 대입 연산자

int result = 0;
result += 10;
System.out.println("result= " + result);
result -= 5;
System.out.println("result= " + result);
result *= 3;
System.out.println("result= " + result);
result /= 5;
System.out.println("result= " + result);
result %= 3;
System.out.println("result= " + result);

3.11 삼항(조건) 연산자

삼항연산자(피연산자1? 피연산자2: 피연산자3)는 총 3개의 피연산자를 가진다.
?앞의 피연산자는 boolean 변수 도는 조건식이 오므로 조건 연산자라고도 한다.
이 값이 true이면 콜론: 앞의 피연산자가 선택되고 false이면 콜론뒤 피연산자가 선택된다.
피연산자 2와 3 에는 주로 값이 오지만 경우에 따라서 연산식이 올 수 있다.

int score = 85;
char grade = (score > 90) ? 'A' : ((score >80) ? 'B' : 'C');
System.out.println(score + "점은 " + grade + "등급입니다.");

3.12 연산의 방향과 우선순위

+ - 보다는 * / 연산자가 먼저
대부분의 연산자는 왼쪽에서 우측으로
대입연산자는 우측에서 왼쪽으로 a = b = c = 5 c=5 b=c a=b가 되는거
()는 ()부터