본문 바로가기
Kotlin

[Kotlin] Kotlin 기본 문법 정리

1. 함수

리턴타입이 없는 경우 즉, 자바에서의 void가 코틀린에서는 Unit 이다. 또한 이는 생략이 가능하다. 

package com.example.kotlin

fun main () {
    val result = test2(1,2)
    val result2 = test3(1,c=5) // 매개 변수를 전부 입력하지않고 지정해줄 수 있다.
    println(result2)
}

//2.함수

fun test() : Unit { // Unit이 생략되어있는데 이 친구는 void 와 동일화다
    println("test")
}

fun test1() : Int {
    return 1
}

fun test2(a: Int, b: Int) : Int { // 매개변수는 변수가 나오고 자료형이 나온다
    println(a+b)
    return a+b
}

// 코틀린에서는 오버로딩이 필요없다 이렇게 디폴트 값 선언할 수 있다. 이렇게 코드를 줄여 간결성있는 코드를 작성가능함
fun test3(a: Int, b: Int = 3, c: Int = 4) : Int { // 매개변수는 변수가 나오고 자료형이 나온다
    println(a+c)
    return a+b
}

fun times(a: Int, b:Int) : Int{
    return a+b
}

fun times2(a: Int, b:Int) = a+b // 위와 아래는 동일하다 single expression

// trailing comma

2. 변수 

  • val = value (값) : 변경이 불가능하다
  • var = variable (변경가능한) : 변경이 가능하다
  • val 인지 var 인지 먼저 알려준 후 변수명, 타입, 값 순으로 작성하면 된다
  • 코틀린의 타입 추론 기능 때문에 val 의 경우엔 타입을 작성해주지 않아도 컴파일 오류가 나지 않는다. 
fun main() {

val a : Int = 3
var b : Int = 4

a = 20 // 오류 발생  ( val은 값을 변경불가)

val name = "죵" // 타입 추론 기능 때문에 타입 생략이 가능하다.

}

 

3. 클래스

  • 코틀린에서는 클래스 생성자 & 속성의 값 할당을 동시에 할 수 있다. 
  • default value 를 넣을 수 있다.
  • 초기화 방식은 주 생성자 뿐만 아니라 init 블럭 , 부 생성자를 이용할 수 있다.
  • 호출 순서는 init 블럭 이후에 부 생성자가 호출된다.
fun main() {
val user = User("죵",10)

//name을 private 이라 지정했기에 user.name 이런식의 접근은 불가능하다.

val users = Users("죵") // 아래의 Users 클래스에서 age 는 값을 지정해줬기에 이름만 작성해도 오류 X
}

class User(private val name : String, var age: Int) // 구현부가 없는 경우엔 한줄로 
// 작성이 가능하기 때문에 생성자의 역할도 가능해진다

class Users(val name : String, var age: Int = 3) // 함수에서와 동일하게 값을 지정해줄수도 있다. default value

 

  • 기본적으로 코틀린에서는 상속을 권장하지 않는다. 클래스를 상속할 수 있게 하려면 클래스 앞에 open을 작성해줘야한다.
  • 생성자가 다른 방식으로 생성될 수 있다. 즉, 주 생성자 이외에 부 생성자를 만들 수 있다.
open class User(open val name: String, open var age: Int) 
class Kid(override val name: String, override var age: Int) : User(name, age) 
// 아이들은 user를 상속받을 수 있다.
// 현재 사용하고 있는건 주 생성자 
// 주 생성자란 아래처럼 클래스명 뒤에 constructor 가 생략이 되어있는 것

class Kid constructor(override val name: String, override var age: Int) : User(name, age)

class Kid (override val name: String, override var age: Int) : User(name, age){
    
    init { // 클래스 내에서 가장 먼저 호출되는 녀석
    	println("초기화 중 입니다.")
    }
    
    // secondary constructor 부 생성자
    var gender: String = "female"
    constructor(name: String, age: Int, gender: String) : this(name, age){
    	this.gender = gender
    }
}

 

4. Null

  • 코틀린에서는 자바와는 다르게 랭귀지 레벨에서 Null에서 안정성을 가져갈 수 있다.
  • 기본 변수 타입에는 null 값을 부여할 수 없다.
  • 타입 뒤에 ?를 붙이면 null이 가능하다. Null 허용
  • !! 는 해당 변수가 현재 널 값이 아니라고 컴파일러에게 알려줘서 컴파일 에러가 나지 않도록 할 때 사용한다.
  • 컴파일 단계에서 에러가 난다.
  • 또한 흔히 null safe 하게 코딩하기 위해서 조건문을 통해 확인해준다. 하지만 코틀린에서는 elvis operation을 사용해 ?:의 왼쪽 객체가 non null이면 그 객체의 값이 리턴되고, null이라면 ?:의 오른쪽 값을 리턴한다.
  • 변수 자체는 nullable 한 타입이지만 반드시 nullable 하지 않을 수 있다. 이 경우엔 val size = nickname!!.length 와 같이 !!를 사용해줘야한다. 하지만 되도록 쓰지 않고 타입을 선언 시 신경써주는 것이 좋다.
fun main() {
	var name: String = "상아"
    name = null // 빨간줄
    
    var nickname: String? = null //타입 뒤에 ?를 붙이면 null이 가능하다.
    
    
    val nickname = if(nickname == null){ //nullsafe 하게 코딩하기 위해 이렇게 작성했던게 대부분이였다.
    	"값이 없음"
    }else {
    	nickname
    }
    
    nickname = "안녕"
    val result = nickname?: "값이 없음" // elvis operation 만약 널이면 오른쪽 값을 내뱉어라
    
    val size = nickname?.length 
    //이렇게 하게되면 만약 nickname이 null인 경우엔 더 이상 진행하지 않고 null을 내뱉어
    //만약 null 이 아니면 길이를 내뱉어
    
}

 

5. String template

  • 로그찍을 때 유용하다.
  • 자바에서는 String 이 아닌경우 toString()을 사용해서 변환해서 보여줬다. 하지만 코틀린에서는 " " 내에 $변수명을 작성해주면 String 형으로 변환되어 보여준다.
  • 또한 변수에 해당하는 메서드도 사용이 가능하다.  { } (bracket) 내에 변수.메서드명 작성 
fun main() {
	val a = 10
    val name = "안녕"
    val isHigh = true
    
    println(a.toString() + name + isHigh.toString()) // 자바의 경우
    println("$a $name $isHigh") // 코틀린
    // 10 안녕 true 결과값이 이렇게 나오게 된다.
    
    println("$a ${name.length} $isHigh") // 코틀린
    // 10 2 true 결과값이 이렇게 나오게 된다.
}

 

 

6. 조건식

  • if-else 와 when이 있다.
  • 자바에서의 조건문은 state 라면 코틀린에서는 expression 임. 즉, 값으로 사용할 수 있다.
  • 삼항연산자는 없다. 대신 아래와 같이 간단하게 표현은 가능하다.
  • when 절에서는 다양한 타입의 데이터를 비교할 수 있다. ex) 범위 혹은 list 등
더보기
    val number : Int = if (a>20) 10 else 20
fun main(){

val a = 0
if(a>3){
	println("3보다 작습니다")
}
}


fun main(){

val a = 0
val i = if(조건){
	// 내용 1
}else if (조건 2){
	// 조건 2
}else{
	// 이외의 내용
}
} // 이런식으로 값으로 사용할 수 있다는 뜻임

fun main(){
when (a) {    
    case1 -> 동작1
    case2 -> 동작2
    else -> 동작3
}
}

fun main(){
when (a) {    
    case1,
    case2 -> 동작2
    else -> 동작3
}
} // 만약 같은 동작을 수행하는 경우엔 아래처럼 묶어줄 수 있다.

fun main() {
    val x = 5
	when (x) {
    	in 1..10 -> println("x는 1~10 사이에 있는 수")
        in listOf(1,2,3,4) -> println("list안에 있는 수")
    	else -> println("x는 다른 수")
	}
} // 다양한 타입의 데이터를 비교할 수 있다.

7. 반복문

  • for 문, while 문,  do-while 문 등이 있다.
  • downTo는 어디까지 감소시킬지 범위를 지정하는 것이다.
fun main(){
	for(i in 범위) // ex) 1..10 는 1이상 10이하를 말한다{
    //반복내용 작성
    }
}

fun main(){
	val arr = arrayOf(1,2,3,4,5) //arrayOf는 배열을 생성하는 함수
	for(i in arr){
    print(i) // 이렇게 하면 배열요소 전부 나온다
    }
}

fun main(){
	for(i in 범위 step(증가하는 크기)) {
    print(~~) //만약 범위가 0..10 이고 step이 2면 0,2,4,6,8,10 이런식으로 출력
    }
}

fun main(){
	for(i in 10 downTo 0 step 2){
    	println(i)
    }
} // 변수의 값을 갑소시키고 싶은 경우 ! downTo는 for문에서 변수를 감소시키는 범위를 지정하는 것이고 변수의 값을 
어디까지 감소시킬지 지정하는 것이다. 위의 예제는 10부터 0까지의 범위를 지정하고 step을 써서 2씩 감소하라고 한 것이다.

fun main() {
    var i = 0
    
    while (i < 5) {
        println(i)
        i++
    }
}

8. 컬렉션

  • 값이 변경가능한 mutable 과 변경불가능한 것으로 나뉜다.
  • list, set, map 등이 있다.

9. 타입체크와 캐스팅

  • is, as 를 사용한다.
fun main(){
    val data: Any = "Hello, World!"

    when (data) {
        is String -> println("string 입니다")
        is Int -> println("int 입니다")
        else -> println("다른 타입 입니다")
    }
}

fun cast(a : Any) {
	val result = (a as? String) ?: "실패" //as를 통해서 캐스팅할 수 있고 ?를 붙이면 캐스팅이 안되는 exception 상황에서 null을 내뱉는다.
}

fun smartcast(a: Any): Int {
	return if(a is String){
    	a.length //스마트캐스팅 즉, 캐스팅 후에 해당 변수타입과 동일하게 바로 사용가능하다.
    }

}