본문 바로가기
개발~/JAVA

Kotlin 소개

by 보배곰 2022. 12. 10.

인프런~
윤재성의 Google 공식 언어 Kotlin 프로그래밍 시작하기

https://www.inflearn.com/course/%EA%B5%AC%EA%B8%80-%EA%B3%B5%EC%8B%9D-%EC%BD%94%ED%8B%80%EB%A6%B0-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0/dashboard

자바 개발자를 위한 코틀린 입문(Java to Kotlin Starter Guide)

https://www.inflearn.com/course/java-to-kotlin/dashboard

https://kotlinlang.org/

[Kotlin Programming Language

kotlinlang.org](https://kotlinlang.org/)

Kotlin 언어 특징

  • Null 안정성을 위해 Null 허용 변수와 허용하지 않는 변수를 구분하여 사용 가능
  • 예외 처리를 강제하지 않음
  • 모든 기본 자료형 값을 객체로 관리
  • 객체지향 프로그래밍과 함수형 프로그래밍 방식 모두 가능
  • Kotlin -> java -> .class
  • Spring Framework 5 부터 Kotlin 을 공식 지원

개발 환경 구축

  • JDK 8.0 (JDK는 6.0 이상 설치 필요)
  • IntelliJ

Main.kt 파일 생성 후, 인텔리제이 Tools > Kotiln > Show Kotlin Bytecode 로 bytecode, bytecode 에서 decompile된 자바코드를 확인할 수 있다.

기본 문법

주석

// 한 줄 주석 

/*
여러 줄 주석
 */

// bytecode 로 변환되지 않음.

println("값 : " + 100)
println("값 : ${100}")

세미콜론

println("세미콜론 없음")
println("세미콜론 있음");

println("1"); println("2"); println("3")

kotlin에서 자료형은 모두 객체로 관리 primitive type 이 없다. ( kotiln에서 box / unboxing 을 알아서 처리해준다. )

변수 선언

var: 선언 이후 값을 다시 저장할 수 있다.

val: 선언 이후 값을 다시 저장할 수 없다.

타입 생략시 저장하는 값에 따라 자료형 결정된다.

코틀린은 자료형 생략을 추천한다.

val 사용을 권장한다 ( val 로 만들고 필요시 var 로 변경 )

null 허용 변수

변수를 선언할 때 null 허용 여부를 설정할 수 있다.

  • var/val 변수명:자료형 = 값
    • null을 허용하지 않는 변수
  • var/val 변수명:자료형? = 값
    • null을 허용하는 변수

null 허용 변수에 null 허용하지 않는 변수를 세팅할 수 있다.

var a1 = 100
var a2: Int? = a1

null 허용하지 않는 변수에 null 허용 변수를 세팅할 수 없다.

다만, 강제로 넣어주고 싶다면 뒤에 !! 를 넣어준다.

var a1: Int? = null
// var a2: Int = a1 // error
var a3: Int = a1!! // 실행시 exception 발생

Safe call ?.

null이 아니면 실행하고, null이면 실행하지 않는다.

val str: String? = "A"
//    println(str.length)  // compile error
println("A.length : ${str?.length}")    // 1

val str2: String? = null
//    println(str.length)  // compile error
println("null.length: ${str2?.length}") // null

Elvis 연산자 ?:

앞의 연산 결과가 null이면 뒤의 값을 사용

val str3: String? = "AB"
println(str3?.length ?: 0)    // 2

val str4: String? = null
println(str4?.length ?: 0)    // 0

Kotlin에서 Java 코드를 가져다 쓸 때,

코틀린에서 자바에 있는 해당 코드가 nullable 인지 notnull 인지 모를 경우, 코틀린이 null 관련 정보를 알 수 없는 타입인 경우 플랫폼타입이라고 하고 실행시 Exception이 발생할 수 있다.

Kotlin에게 알려주기 위해 @Nullable, @Notnull 어노테이션을 활용할 수 있다. (javax.annotation , org.jetbrains.annotation )

// java code 
public class Person {

    private String name;

    @Nullable
    public String getName() {
        return name;
    }
}

Kotlin에서 Java 코드를 활용할 경우 annotation을 활용/확인하거나 코틀린으로 wrapping 해서 자바 코드 가져오는 부분을 최소화할 수 있다.

기본 타입 간의 변환

java: 기본 타입 간의 변환이 암시적으로 이뤄질 수 있다.

// java 
public static void main(String[] args) {
    int num1 = 1;
    long num2 = num1;
    System.out.println("num1 + num2 = " + num1 + num2);
}

내부적으로 int 타입의 값이 long 타입의 값으로 암시적으로 변경되었다.

kotlin: 기본 타입 간의 변환이 명시적으로 이뤄져야한다.

val num1 = 4
// val num2: Long = num1   // error
val num2: Long = num1.toLong()

타입 캐스팅

타입을 체크한 뒤 사용을 위해서는

java 는 instanceof 사용 후 (타입) 을 적어주어야 한다.

// java 
void typeCasting(Object obj) {
    if (obj instanceof String) {
        String str = (String) obj;
    }
}

kotlin 은 java의 instanceof 와 동일한 의미로 is 를 사용한다.

(타입) 대신 as 타입 을 사용하나 생략가능하다.

// kotlin
fun typeCasting(obj: Any) {
    if (obj is String) {
        val str = obj as String    // as String 생략 가능
    }
}

해당 타입이 아니라는 의미로 !is 를 사용한다.

// kotlin
fun typeCasting(obj: Any) {
    if (obj !is String) {

    }
}

null 이 들어온다면?

// kotlin
fun typeCasting(obj: Any?) {
    val str = obj as? String
}

함수

Java에서는 클래스에 메서드를 만들어 사용하지만 Kotlin은 C 언어처럼 한수라는 개념을 제공한다.

fun 함수명(매개변수): 반환타입 {
...
}

// 매개변수는 변수명: 자료형 형태
fun 함수명(변수명: 자료형,...): 반환타입 {
...
}

함수 호출시 매개변수를 지정하여 호출할 수 있다.

fun main() {
    test(1, 1.1)
    test(a2 = 2.2, a1 = 2)
}

fun test(a1: Int, a2: Double) {
    println("a1: $a1")
    println("a2: $a2")
}

기본 값이 설정된 매개변수

fun main() {
    test(3)
    test(a2 = 3.3)
}

fun test(a1: Int = 0, a2: Double = 0.0) {
    println("a1: $a1")
    println("a2: $a2")
}

반환타입

fun main() {
    val r1: Int = test(100, 200)
    println("r1: $r1")
}

fun test(a1: Int, a2: Int): Int {
    val result: Int = a1 + a2
    return result
}

// 반환타입 없음 : Unit 생략가능
fun test2() : Unit {
    println("test2--- ")
}

지역 함수

  • 함수 내에 정의한 함수
  • 함수를 정의한 함수 안에서만 호출이 가능
fun main() {
    test()
}

fun test() {

    println("test8")

    fun test9() {
        println("test9")
    }

    test9()
}

Kotlin은 함수로만 프로그램 작성이 가능하다.

연산자

단항 연산자

  • +a: 양수 -> 양수 , 음수 -> 음수
  • -a: 양수 -> 음수, 음수 -> 양수
  • !a: true -> false, false -> true
  • a++ (val X , var O)
  • a-- (val X , var O)
  • ++a (val X , var O)
  • --a (val X , var O)

산술 연산자

  • +
  • -
  • *
  • /
  • %
  • ..

대입 연산자

  • +=
  • -=
  • *=
  • /=
  • %=

비교 연산자

  • ==
  • !=
  • >
  • <
  • >=
  • <=

제어문

IF 문

주어진 조건에 따라 작성된 코드 수행 여부를 결정

if (조건문) {
...
} else if(조건문) {
...
} else {
...
}
val a: Int = 10

val str: String = if (a == 10) "10입니다." else "10이 아닙니다"
println(str)

val str2: String = if (a == 10) {
    println("10입니다.")
    "10입니다."
} else {
    println("10이 아닙니다.")
    "10이 아닙니다."
}

println("str2: $str2")

When

java 의 switch 문과 비슷하지만 다르다.

when(값) {
    조건 -> ...
    조건 -> {
        ...
    }
}

// else 는 필요하면 추가 가능 
when(값) {
    조건 -> ...
    조건 -> {
        ...
    }
    else -> ...
}

조건에 , 를 넣어서 or 조건을 만들 수 있다.

// or 
when(값) {
    조건, 조건 -> ...
}

when(5) {
    1, 2, 3 -> println("1,2,3 중 하나")
    4, 5 -> println("4,5 중 하나")
}

조건에 범위를 지정할 수 있다.

// range
when(값) {
    in 범위 -> .. 
}

when(5) {
    in 1..3 -> println("1~3 범위 내")
    in 4..6 -> println("4~6 범위 내")
}

값을 반환받을 수도 있다.

fun main() {
    val str1 = setValue(1)
    println("str1: $str1")
}

fun setValue(a1: Int) = when(a1) {
    1 -> "1"
    2 -> "2"
    else -> "그 외"
}

반복문

for , while, do-while 문을 제공한다.

val a1 = 1..10
for (item in a1) {
    println("a1: $item")
}

val a2 = 1..10 step 2
for (item in a2) {
    println("a2: $item")
}

val a3 = 10 downTo 1
for (item in a3) {
    println("a3: $item")
}

var a5 = 0
while (a5 < 10) {
    println("a5: $a5")
    a5++
}

var a6 = 0
do {
    println("a6: $a6")
    a6++
} while (a6 < 10)

break, continue 를 제공한다.

for (item in 1..10) {
    if (item > 5) {
        break
    }
    println("$item")
}
println("----------")
for (item in 1..10) {
    if (item % 2 == 0) {
        continue
    }
    println("$item")
}

return 이 없는 함수를 변수로 받아 print하면, kotlin.Unit 으로 나온다.

fun main() {
    var r3 = testFun3(0)
    println("r3: $r3")    // r3: kotlin.Unit
}


fun testFun3(a: Int) {
    if (a == 0) {
        return
    }
    println("testFun3: $a")
}

클래스

// 정의
class 클래스명 {

}

// 내용이 없다면 아래처럼 사용도 가능
class 클래스명 

// 사용
fun main() {
    val c = 클래스명()
}

init : 객체 생성지 자동으로 처리되는 코드 ( 입력값을 받을 수는 없다.)

생성자 : 객체 생성시 실행되는 코드 (입력값을 받을 수 있다.)

init

class TestClass1 {

    init {
        println("call init")
    }
}

constructor

class TestClass1 {

    var v1 = 0
    init {
        println("call init")
    }

    constructor() {
        println("call constructor()")
    }

    constructor(v1: Int) {
        println("call constructor(v1)")
        this.v1 = v1
    }
}

 

 

class 정의시 아래와 같이 작성하면 생성자가 바로 만들어진다.

class 클래스명(변수명:타입...)

// kotlin 
class TestClass2(a1:Int, a2:Int)

// java 
public final class TestClass2 {
   public TestClass2(int a1, int a2) {
   }
}

class 정의 시 아래와 같이 작성하면 생성자 뿐 아니라 멤버 변수, 필요시 get,set 메서드도 함께 만들어 준다.

class 클래스명(var,val 변수명:타입...)

// kotlin
class TestClass3(var a1:Int, val a2:Int)
// class TestClass3 constructor(var a1:Int, val a2:Int)	// constructor 생략 가능

// java 
public final class TestClass3 {
   private int a1;
   private final int a2;

   public final int getA1() {
      return this.a1;
   }

   public final void setA1(int var1) {
      this.a1 = var1;
   }

   public final int getA2() {
      return this.a2;
   }

   public TestClass3(int a1, int a2) {
      this.a1 = a1;
      this.a2 = a2;
   }
}

 

호출 순서

fun main() {
    val testClass3 = TestClass3(1)
    println("testClass3.a1 = ${testClass3.a1}")
    println("testClass3.a2 = ${testClass3.a2}")
}

class TestClass3(var a1: Int, val a2: Int) {	// 주 생성자
    init {
        println("TestClass3: call init")
        println("a1: ${a1}")
        println("a2: ${a2}")
    }

    constructor(a1: Int) : this (a1, 100){	// 보조 생성자
        println("TestClass3: constructor(a1)")
    }
}

선택한 보조생성자 접근 -> 주 생성자 실행 -> init 코드 실행 -> 선택한 보조생성성자 실행 

'개발~ > JAVA' 카테고리의 다른 글

[Spring boot] page 1부터 시작하기  (0) 2020.04.30
Log4j 사용하기  (0) 2019.12.19
JSON 빈 객체를 단말에 어떻게 내려줄까?(Android,iOS)  (0) 2019.04.25
주석이쁘게 달기  (0) 2017.06.16
[JAVA] java.util.Date  (0) 2017.03.17

댓글