[native_Android] Kotlin(1) 기본 문법(압축)
가장 기본적인 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)
}