카테고리 없음

[native_Android] Kotlin(1) 기본 문법(압축)

Dalcomi20 2021. 9. 7. 17:51

가장 기본적인 class definition이다.

class Person(
    val name: String,
    var isMarried: Boolean
)//the properties are given default accessors.

//instantiation
val person = Person("Bob", true)
println(person.name + " is${if(
    !person.isMarried) "not" else ""} married");

1. immutable 을 애용하자!

val 은 immutable이다. 한번 assign 되면 다시 assign할 수 없다. 

var 은 mutable이다. 함수형 프로그래밍의 원칙에 따라 가능하면 val을 사용하고

꼭 필요한 것들만 var로 바꾸어 주자.

 

2. if 는 expression으로 사용될 수 있다!

string에서 ${ ... } 안에는 expression이 들어갈 수 있다.

if 문은 expression이다. 즉, 값을 갖는다. control이 다 statement여서 저렇게 사용될 수 없는 Java와 대조적!

 

packages and imports

 

이번엔 간단하게 한 파일에서 class를 정의하고, 다른 파일에서 그 class를 사용해보자.

IntelliJ에서 kotlin(JVM) with gradle 으로 만들어진 프로젝트이다.

다음과 같이 kotlin 폴더가 src 폴더로 파랗게 잡혀있는 것을 볼 수 있다.

kotlin에서는 java와 다르게, 꼭 package 구조가 project의 directory 구조를 따를 필요가 없다.

하지만 project구조를 package구조와 같게 가져가는게 good practice.

 

먼저 geometry.shapes 패키지에 rectangle을 추가해준다.

Rectangle.kt

package geometry.shapes
import java.util.Random

class Rectangle(val height: Int, val width: Int){
    val isSquare: Boolean //a property with custom getter
        get() = height == width //again, an expression function
}

fun createRandomRectangle(): Rectangle {
    val random = Random()
    return Rectangle(random.nextInt(),random.nextInt())
}

createRandomRectangle을 geometry.example 패키지의 Main에서 사용할 것이다.

import geometry.shapes* 로 그 패키지에 정의된 모든 이름을 쓸 수 있다.

 

Main.kt

package geometry.example
import geometry.shapes.*

fun main(args: Array<String>){
    println(createRandomRectangle().isSquare)
}

 

control : when

기본적으로는 java의 switch-case와 비슷한 동작이다. 하지만 when은 값을 가질 수 있는 expression이다.

즉, function 에서 바로 return 하거나, 다른 variable에 assign 할 수 있다.

 

이 예시에서는 enum class color 을 만들어

그에 대한 expression으로 분기하는 function을 만든다.

(물론, 단지 equality check를 위해서 계속 set 객체를 만드는 것은 비효율적이다.

아예 when을 parameter없이 T/F를 판단할 수 있는 boolean expression으로

equality check를 대신하는 방법을 생각해볼 수 있다.)

 

enum class Color(
    val r: Int, val g: Int, val b:Int
){
    RED(255, 0, 0),
    GREEN(0, 255,0),
    BLUE(0, 0, 255),
    YELLOW(255, 255, 0),
    ORANGE(255, 165, 0),
    INDIGO(75, 0, 130),
    VIOLET(238, 130, 238);
    //semicolon required!

    fun rgb() = (r * 256 + g) * 256 + b
}

fun mix(c1: Color, c2: Color) =
    when (setOf(c1, c2)){
        setOf(Color.RED, Color.YELLOW) -> Color.ORANGE
        setOf(Color.BLUE, Color.YELLOW) -> Color.GREEN
        setOf(Color.BLUE, Color.VIOLET) -> Color.INDIGO
        else -> throw Exception("Dirty Color")
    }

nullables and the Elvis operator

 

type에 ?를 붙이면 nullable type이 된다. nullable type은 null을 point할 수 있다.

따라서 nullable type에 대해서는 그 짜증나는 null pointer exception (NPE) 가 안 발생한다!

 

nullable variable의 property를 access 할 때에는 당연히 그  variable이 null을 가리키고 있을

가능성을 생각해야 하는데, is not null 체크 대신 ?. 라는 간단한 safe call operator를 사용한다.

 

마지막으로 만약 어떤 expression이 null이면 다른 expression으로 대체할 수 있게 elvis operator가 있다.

?: 왼쪽의 expression 이 null 이면 그 오른쪽의 expression이 evaluate된다.

 

data class Message(
    val value: String?
)

fun main(){
    val listWithNulls: List<Message?> = listOf(Message("hi"), null, Message(null))
    for (msg in listWithNulls) {
        msg?.let{println(msg.value ?: "no message")}
    }
}

exceptions - try ... catch

 

1. java에서는 function이 throw할 수 있는 exception을 

    fun foo(..) throws ...Exception 이렇게 써주어야 한다. 하지만 kotlin에서는 그런 거 없다.

 

2. try 역시 expression으로 그 값을 다른 variable에 assign할 수 있다.

그럼 try 블록의 값은 뭔데? block의 마지막 expression의 값이 곧 그 block의 값이다.

 

bufferedReader을 통해 숫자를 읽어 출력하는 예시.

BufferedReader.readLine() 은 String을 반환하기 때문에 정수값을 원하면 parseInt를 꼭 해주어야 한다.

fun readNumber(reader: BufferedReader){
    val num = try{
        Integer.parseInt(reader.readLine())
    }catch (e: NumberFormatException){
        null
    }

    println(num)
}