이것이 자바다 (03.연산자)

오늘·2021년 2월 23일
0

Java

목록 보기
5/42

3.1 연산자

  • 연산(operations) = 프로그램에서 데이터를 처리하여 결과 산출하는 것
    연산자(operator) = 연산에 사용되는 기호나 표시 (+, -, * …)
    피연산자(operand) = 연산되는 데이터 (변수 x, y, z …)
    연산식(expressions) = 연산자와 피연산자를 이용하여 연산의 과정을 기술한 것

3.2 연산 방향과 우선순위

  1. 단항, 이항, 삼항 연산자 순으로 우선순위를 가진다
  2. 산술, 비교, 논리, 대입 연산자 순으로 우선순위를 가진다
  3. 단항과 대입 연산자를 제외한 모든 연산의 방향은 → (왼쪽에서 오른쪽)
  4. 복잡한 연산식에는 괄호()를 사용해 우선순위를 정해줄 수 있다.

3.3 단항 연산자

3.3.1 부호 연산자

  • 양수 및 음수를 표시하는 + 와 -를 말한다.
  • boolean 타입과 char 타입을 제외한 나머지 기본 타입에 사용 가능하다.

3.3.2 증감 연산자

  • 변수의 값을 1 증가(++) 시키거나 1 감소(--) 시키는 연산자
  • boolean 타입을 제외한 모든 기본 타입의 피연산자에 사용할 수 있다.
  • 결국 값은 비슷하게 나와도 원하는 식에 사용하기 위해서는 차이를 알아둬야한다.

    int x = 10;
    int y = 10;
    int z = ++x +1
    //현재 z 값 = 12, 연산 후 저장
    int k = y++ + 1
    //현재 k 값 = 11 연산 전 저장

3.3.3 논리 부정 연산자

  • !
  • 조건문과 제어문에서 조건식의 값을 부정하도록 해, 실행 흐름을 제어할 때 주로 사용된다.
  • 두 가지 상태(true, false)를 번갈아가며 변경하는 toggle기능을 구현할 때 주로 사용한다.
    ex) 스위치, caps lock, num lock

3.3.4 비트 반전 연산자

  • ~
  • 정수타입(byte, short, int, long)의 피연산자에만 사용한다.
  • 피연산자를 2진수로 표현했을 때 비트값인 0 → 1, 1 → 0 으로 반전한다.
  • 산출은 int 타입으로 나온다.
byte v1 = 10;
//byte v2 = ~v1; // 에러
int v2 = ~v1; // 가능

3.4 이항 연산자

  • 피연산자가 두 개인 연산자를 말한다.

3.4.1 산술 연산자

  • 사칙 연산자(+, -, *, /)와 나머지(%) 연산자
  • int → int
    float → float
    double → double
    산술 연산시 피연산자들의 타입을 맞춰주어야 한다.
  • 자바에서 리터럴 간의 연산은 타입 변환 없이 해당 타입으로 계산된다.
    따라서 다음과 같은 char 타입 연산은 문제가 없다.
char c1 = 'A' + 1;
// 유니코드에 1을 더해 c1에 저장. 실행 결과 : B

하지만 이런경우는 문제가 된다.

char c2 = 'A';
// char c3 = c2 + 1; //에러
// c2가 이미 int 타입으로 변환이 된 상태이기 때문에 타입이 달라 에러

이런 경우에는 타입을 강제 변환 후 다시 char 타입으로 얻을 수 있다.

char c3 = (char) (c2 + 1);
// 강제변환 후 계산 가능!

오버플로우 탐지

  • 산술 연산시 주의 점은 연산 후 산출값이 산출 타입으로 충분히 표현 가능한가 봐야하는 것이다. 표현할 수 없는 값이 나왔을 경우, 오버플로우가 발생하고 쓰레기값을 얻을 수도 있기 때문이다.
int x = 1000000;
int y = 1000000;

int z = x * y;
//z 값 : -727379968 같은 이상한 값이 나온다

위와 같은 경우. 계산 값이 int 범위를 벗어났기 때문에 코드 자체에 에러는 나지 않지만 올바른 값이 나오지 않는다.

// x와 y 중 하나라도 long 타입이어야 하고
// 변수 z가 long 타입이어야 한다
long x = 1000000;
long y = 1000000;

long z = x * y;
//실행결과 올바른 값이 나온다.
  • 피연산자를 사용자로부터 입력받거나 프로그램 도중 데이터가 생성될 경우, 항상 결과값과 타입을 예상할 수 있는건 아니기에 예외처리 메소드를 사용하기도 한다.
public class chap3_checkOverflowExam2 {
	public static void main(String[] args) {
		try {
			int result = safeAdd(2100000000, 200000000);
			System.out.println(result);
		} catch (ArithmeticException e) {
			System.out.println("오버플로우가 발생하여 정확하게 계산할 수 없음");
		} // 예외처리코드
	}

	public static int safeAdd(int left, int right) {
		if ((right > 0)) {
			if (left > (Integer.MAX_VALUE - right)) {
				throw new ArithmeticException("오버플로우 발생"); // 예외발생코드
			}
		} else {// right<=0 일 경우
			if (left < (Integer.MIN_VALUE - right)) {
				throw new ArithmeticException("오버플로우 발생"); // 예외발생코드
			}
		}
		return left + right;
	}
}
  • 정확한 계산을 해야할 때는 실수 타입보다는 정수 타입이 좋다.
    부동소수점 타입(float, double)은 0.1을 정확히 표현할 수 없어 근사치로 처리하기 때문이다.
  • / 와 % 사용시에도 주의점이 있다.
    좌측 피연산자가 정수 타입인 경우 나누는 우측 피연산자는 0을 사용할 수 없다.
  • 예외 발생시 자바는 프로그램 실행을 즉시 멈추고 종료된다. 따라서 예외처리를 해주어야 한다.
 //5/0 // ArithmeticException 예외 발생
 //5%0 // ArithmeticException 예외 발생
 //컴파일은 되지만, 실행시 ArithmeticException (예외) 발생
 
try{
   //int z = x / y;
   int z = x % y;
   //0일 경우 ArithmeticException발생 -> 예외 처리로 가게 됨
   System.out.println("z: " +z);
} catch(ArithmeticException e) {
    //예외 처리
    System.out.println("0으로 나누시면 안됩니다")
}

NaN & Infinity

  • 만약 실수 타입인 0.0 또는 0.0f 로 나누면 예외가 발생하지 않고
    / 연산 결과는 무한대 (Infinity) 값을 가지며
    % 연산 결과는 NaN(Not a Number) 을 가진다.
  • 이 경우에는 다음 연산을 수행해서는 안 된다. 어떤 산술 연산을 하더라도 Infinity 혹은 NaN 이 산출되어 엉망이 될 수도 있기 때문이다.
// 산출 값인 z가 올바른 값이 아니라면
// if문을 사용해 실행 흐름을 변경해야 한다.
if(Double.isNaN(z)||Double.isInfinite(z)){
  System.out.println("값 산출 불가");
} else{
  System.out.println(z+2);
}
  • 부동소수점(실수)을 입력받을 때는 반드시 NaN 검사를 해야한다. 악의성 있는 사용자가 숫자로 변환이 안 되는 NaN을 입력할 수도 있기 때문이다.
String userInput = "NaN";
double val = Double.valueOf(userInput);

double currentBalance = 10000.0;

if(Double.isNaN(val)) {
//NaN을 검사한다
	System.out.println("NaN 입력으로 처리 불가");
    	//NaN일때 실행되는 코드
    	val = 0.0;
        //변수 val은 NaN이 되는 대신 0.0이 된다.
}

currentBalance += val;
//NaN 대신 0.0이 된 val과 연산되어
//currentBalance 의 원래 값이 유지된다.
System.out.println(currentBalance);

3.4.2 문자열 연결 연산자

  • '+' : 산술연산자, 부호 연산자, 문자열 연결 연산자
  • 피연산자 중 한쪽이 문자열이면 + 연산자는 문자열 연결 연산자로 사용되어, 다른 피연산자를 문자열로 변환하고 서로 결합한다.
String str1 = "JDK " + 6.0;
String str2 = str2 + " 특징";

//str1 : JDK 6.0
//str2 : JDK 6.0 특징
  • 어떤 것이 먼저 나오느냐에 따라 연산의 값이 달라지므로 주의해야한다.
String str1 = "JDK " + 3 + 3.0;
//str1 : JDK 33.0

String str2 = 3 + 3.0 + " JDK";
//str2 : 6.0 JDK

3.4.3 비교 연산자

  • 대소 비교 연산자 <, <=, >=, >), Boolean 타입 외에 모든 타입의 비교 연산에 사용
  • (동등 비교 연산자 ==, !=), 모든 타입의 비교 연산에 사용
  • char 타입이 피연산자이면 유니코드 값으로 비교연산을 수행하게 된다.

3.4.4 논리 연산자

  • &&(논리곱), ¦¦(논리합), ^(배타적 논리합), !(논리 부정)
  • 논리 연산자의 피 연산자는 boolean 타입만 사용이 가능하다.
  • &보다는 &&이, |보다는 ||이 더 효율적으로 동작한다. 앞의 피연산자만으로 산출 결과를 내기때문이다.

3.4.5 비트 연산자

  • 데이터로 비트 단위, 즉 0, 1을 피연산자로 삼아 연산을 수행
  • AND(논리곱) : 두 비트 모두 1일 경우에만 연산 결과 1
    OR(논리합) : 두 비트 중 하나만 1이면 연산 결과 1
    XOR(배타적 논리합) : 두 비트 중 하나 1, 다른 하나 0일때 연산결과 1
    NOT(논리부정) : 보수

3.5 삼항 연산자

  • 세 개의 피연산자를 필요로 하는 연산자이다.
  • 조건식 ? 값 또는 연산식 : 값 또는 연산식
    ? 앞의 조건식에 따라 콜론 앞 뒤의 피연산자가 선택된다고 해 조건 연산식이라 부르기도 한다.
  int score = 95;
  char grade = (score>90) ? 'A' : 'B'
      
  //위 식과 아래 if문은 실행 결과가 같다.
  
  int score = 95;
  char grade;
  if(score>90){
      grade = 'A';
  } else{
      grade = 'B';
  }
  • 한 줄에 간단하게 삽입하여 사용할 경우에는 삼항 연산자를 사용하는 것이 더 효율적이다.

0개의 댓글