내가 보려고 만든 Kotlin 개념 1탄 (Java와의 차이점 중심으로)

Posted by RoadtoS7 on February 09, 2020 · 8 mins read

대략적인 목차

  1. 표현식
  2. 연산자에 관하여
  3. (정수/실수)타입에 관하여
  4. if-else 표현식

표현식(Expression)

  • 하나의 값으로 수렵하는 수식 뭉치
  • 값을 반환한다.
  • 변수에 값을 할당하는데 쓰일 수 있다.
  • 표현식의 결과에는 타입이 존재한다.
    표현식의 타입은 중요! 변수에 값을 저장하려면 변수의 타입과 표현식의 타입이 일치해야 한다.
    ex. val somthing: Int = 결과 타입이 Int 인 표현식



리터럴(Literal)

  • 숫자 값 자체
  • 타입이 존재한다.



% 연산자

  • 나머지 연산자의 일종으로 취급하여서 +, - 연산자보다 우선순위가 높다.



Int / Int 의 결과 타입

  • Int 가 된다.
  • 따라서 소수점 부분이 잘려나간다.
  • 소수점을 살리기 위해서는 결과타입이 Double 되어야한다. 피연산자 중 하나를 Double 로 만들어주면 된다.
val num: Double = 15.0 / 2
val num2: Int = 85 % 7
val num3: Double = num2.toDouble() / num2 + 0.7

코틀린에서 Int 타입을 Double 타입으로 변환할 때 타입 캐스팅이 아닌 toDouble()함수를 이용하는 이유

  • 코틀린에도 형변환 키워드가 존재한다. 하지만 Int 타입은 Double 타입과 상속관계가 아니여서 캐스팅으로는 형변환을 할 수 없다.
  • 그래서 toDouble 이라는 메소드를 이용해서 Int 를 Double 로 형변환한다.



코틀린의 타입 체크

  • 코틀린은 Double 타입 변수에 Int 값을 저장할 수 없다.



비트 연산자

  • 15 and 7 : 15와 7을 비트단위로 and연산한다.
  • 5 or 2 : 5와 2를 비트단위로 or 연산한다.
  • 15 xor 5 : 15와 5를 비트단위로 xor 연산한다.
  • 25767.inv() : 25767을 비트 단위로 반전. 결과: -25676
  • 1 sh1 3 : 1을 왼쪽으로 3칸 시프트
  • 8 shr 1 : 8을 오른쪽으로 3칸 시프트
  • -17 ushr 2 : 부호를 유지한 채 -17을 오른쪽 2칸 시프트



정수 타입과 실수 타입

  1. 정수타입 1) Byte
    • 크기: 1 Byte
    • 저장가능 범위: -128 ~ 127

2) Short

  • 크기: 2 Byte
  • 저장가능 범위: -3만 2768 ~ 3만 2767

3) Int

  • 크기: 4 Byte

3) Long

  • 크기: 8 Byte


  1. 실수 타입
    • 코틀린은 실수를 부동소수점 방식으로 저장한다.
    • 실수타입은 저장 가능 범위가 아닌 소숫점 정밀도를 저장한다.
    • 부동소수점 방식 : 표현하려는 숫자를 유효숫자(1.xxx 형태의 2진수) x 2의 n승 형태로 저장한다.
    • 만약, 표현하려는 숫자가 2진수로 1011.1001일 경우 1.0111001 형태가 되도록 뒤에 2의 -3승을 곱한다. 그리고 이 값들 중 유효숫자인 10111001과 -3만을 저장한다.

1) Float

  • 크기 : 4 Byte

2) Double

  • 크기: 8 Byte
val a: Byte = 125
val b: Short = (100 + 200) + 300
val c: Int = 12_4353_1234
c = 0xFF_88_88
c = 0b01010010_01100011_01110101
val d: Long = -543_7843_1234_5678

c = a + b
d = c + 10L

val e: Float = 67.6f
val f: Double = 658.456
e = (e + f).toFloat()
  • Byte 타입에 저장가능한 경우: Byte 타입 변수에 저장하고자 하는 값이표현식이 리터럴로만 이루어져있고, 그 값이 Byte 타입의 저장 가능 범위 안에 있을 경우에 한에 저장이 가능하다.
  • 숫자 리터럴 안에 언더스코어 _ 를 넣어 숫자를 더 알아보기 쉽게 표현할 수 있다. 언더스코어의 개수와 위치는 마음대로 할 수 있다. 실수타입의 리터럴에도 적용할 수 있다.
  • 정수 리터럴이 0x 로 시작하면 뒤이어 오는 수는 16진수로 인식된다.
  • 정수 리터럴이 0b 로 시작하면 뒤이어 오는 수는 2진수로 인식된다.
  • 정수 리터럴 값이 Int의 범위를 넘어가면 자동으로 Long 타입이 된다. 따라서 -543784312345678 은 Long 타입이다.
  • Int와 Int보다 작은 범위의 정수들( Byte 타입, Short 타입의 정수들) 끼리 연산하면 무조건 Int 타입이 결과로 나온다. 즉 Byte + Byte도 Short + Short 모두 결과로 Int 타입이 나온다.
  • 정수 리터럴 뒤에 L을 붙이면 해당 리터럴은 Long 타입이 된다.
  • Int + Long 은 결과로 Long 타입이 된다. 왜냐하면 결과값이 Int 의 범위를 넘어갈 수 있기 때문이다.
  • 정수 리터럴 뒤에 f를 붙이면 해당 리터럴은 Float 타입이 된다.
  • Double + Float는 결과로 Double 타입이 나온다.
  • 코틀린은 8 진수를 지원하지 않는다.



실수 타입의 함정

  • 실수값은 2진수 유효숫자로 표현되기 때문에 상황에 따라서 값을 정확하게 나타낼 수 없다.
    ex. 10 진수로 0.1 은 2진수로 표현할 때 소수점이 정확히 나눠 떨어지지 않는 무한 소수가 되기 때문이다.
  • 따라서 꼭 실수 값으로 처리해야하는 상황이 아니라면 정수 타입만을 사용하는 것이 좋다.

문자 타입

  • 코틀린은 문자 코드를 맵핑하는 방식으로 유니코드 를 사용한다.
var ch: Char = 'A'
println(ch)
// -> A

ch = '\uAC00'
println(ch)
// -> 가

ch = '한'
println(ch.toInt())
// ->54620
// 컴퓨터는 숫자 값만을 저장할 수 있기 때문에 문자를 저장하기 위해 해당 문자와 매핑된 문자 코드를 저장한다.
// '한'의 문자코드(유니코드) = 54620



문자열(String)

  • 문자열 인덱싱이 가능하다.
    인덱싱 : String 타입의 표현식 우측에 대괄호[]를 적고 대괄호 안에 숫자를 적으면 그 번호에 맞는 문자를 Char 타입으로 꺼낼 수 있다.
    즉, str이 String 타입이라면 str[7]은 Char 타입이다.
  • String 타입의 표현식이라면 무엇이든 대괄호를 사용할 수 있다. 다음도 가능하다.
    ex. “Great”[1]



문자열 안에 표현식의 값 집어넣기

  • 문자열 안에서 $ 다음에 변수 이름을 적으면, 해당 부분은 변수의 값으로 대체 된다.
  • 문자열에서 $ 를 출력하고 싶으면 /$ 를 사용해야 한다.



타입 별명(Type Alias)

  • typealias 별명 = 타입
  • 타입에 새로운 별명을 붙일 수 있다.
 typealias Number = Int
 
 fun main(args: Array<String>): Unit{
  val a: Number = 10
  println(a)
 }
  • 이제 Numer와 Int는 같은 타입이 된다.
  • 타입 별명은 타입이름이 너무 길 때 타입 이름을 줄이는 용도로 사용하면 좋다.



할당 연산자(Assignment Operator)

  • =
  • = 연산자는 값을 반환하지 않기 때문에 = 연산자가 포함된 수식은 표현식이 아니다.



비교 연산자 == != > < >= <=

  • />, <, <=, >= 에서 피연산자의 타입이 일치할 필요가 없다. 둘 다 숫자타입이면 된다.
  • == 에서는 피연산자의 타입이 반드시 일치해야 한다.
  • 0.00001f == 0.005f * 0.002f 의 결과는 false이다. 수학적으로는 0.0001과 0.005 * 0.002 가 같지만 실수 타입의 한계로 인해 두 실수 값을 정확하게 비교하지 못한다.

if-else를 표현식으로 사용하기

  • if와 else 가 모두 갖춰저 있으면 if-else 부분 전체가 표현식이 된다.
    ``` fun main(args: Array): Unit{

val value: Int = if(10 > 5){ println(“10은 5보다 크다”) 10 } else{ println(“10은 5보다 크지 않다.”) 5 }

println(value) }

- if 블록 안의 마지막 표현식의 if-else 표현식의 값이 된다.
- 즉, 위의 예시에서 val value: Int = 10이 된다.
- 위의 예제와 달리 if 가 아닌 else 블록이 실행되는 경우에는 else 블록의 마지막 표현식인 5가 if-else 표현식의 값이 된다.  val value: Int = 5가 된다.
- if 블록과 else 블록의 마지막 표현식의 타입이 일치해야한다. if 블록의 마지막 표현식이 Int 타입이었으면 else 블록의 마지막 표현식도 Int 타입이어야한다.

- if-else의 블록이 비어있거나, 마지막 문장이 표현식이 아니라면 if-else 표현식의 타입이 Unit 가 된다.  아래 예시에서 변수 a와 변수 b는 Unit 타입이 되어서 의미없는 값이 저장된다.

val a = if(10>6){} else{}

// 또는 val b = if(10>5){ val a = 10 } else{ val a = 5 } ```

  • if-else 표현식을 이용하여 삼항 연산자를 사용가능하므로 코틀린에는 삼항 연산자가 존재하지 않는다.