Kotlin (0) 소개 및 기본 문법
오늘은 Kotlin에 관해서 공부하는 시간을 가져보려고 한다!
학부생 시절 Java도 아닌 C++, Python만 주구장창 하다가 지금 와서 Kotlin을 하려니 자바 문법조차 가물가물해서 죽을맛이다.
Kotlin
☝ 왜 Kotlin인가?
몇 년 전까지만 해도 왜 Kotlin을 해야하냐는 의구심과, 질문들이 굉장히 많았었지만, 지금은 여러 지표와 발표들이 곧 Kotlin을 공부해야하는 확실한 이유가 된다.
간단하게 서술해보자면, 다음과 같다.
- 안드로이드 공식 개발자 가이드 1언어
- 위 링크의 가이드에서 어떤 함수를 찾아보던, 이제는 제 1언어가 Kotlin, 두 번째가 Java다.
- 구글의 Kotlin 사랑
- 이제는 유명한 구글의 Kotlin 사랑.
- 2년 전 부터 구글은 안드로이드 개발에서 Kotlin을 지원했으며, 이후 배포하는 모든 라이브러리는 Kotlin으로 배포 할 예정이라고 한다.
- 대세 언어
- 2019년 구글 I/O에서는 프로 안드로이드 개발자의 50%는 이미 Kotlin을 사용하고 있다고 선언하였다.
이 정도면 Kotlin을 공부해야 하는가에 대한 질문에 충분한 대답이 될 것이라고 생각한다!
🤞 기초 문법
후술할 Kotlin 함수들을 직접 작동시켜 보고 싶다면 Kotlin Playground를 온라인 ide로 이용하면 편하다.
2.1 변수 정의
Java
public int age = 17;
Kotlin
val age: Int = 17
val age = 17
Kotlin에서는 변수형을 지정하지 않고 변수를 정의하여도 컴파일러가 자동으로 추론하도록 되어있다.
val age = 17
age = 20 // 컴파일 에러 발생
Result
! Val cannot be reassigned
val
은 java의 final과 같은 역할을 한다.
변경할 수 있는 형태로 선언하기 위해서는 var 형식으로 선언하면 된다.
var age = 17
age = 20 // 가능!
2.2 Single Expression return
Java
public int power(int x) {
return x * x;
}
Kotlin
fun pow(number: Int): Int {
return number*number
}
fun main() {
println(pow(4))
}
Result
16
Kotlin
fun double(number: Int) = number*2
fun main() {
println(double(4))
}
Result
8
experssion으로 사용 할 때는 return 타입을 명시 하지 않아도 된다. (선택적으로 사용하면 된다!)
2.3 Null 연산자
2.3.1 Nullable Type (?)
Kotlin
fun double(number: Int) = number*2
fun main() {
println(double(4))
println(double(null)) // 컴파일 에러
}
Result
! Null can not be a value of a non-null type Int
Kotlin에서는 위처럼 선언된 함수의 생성자(number
)에 null을 넣을 수 없기에, 위 함수를 실행하면 컴파일 에러가 발생한다.
만약 null을 넣는 시도를 하게 된다면, 컴파일 에러가 발생한다.
이를 방지하기 위한 함수는 아래와 같다.
Kotlin
fun doubleSafe(number: Int?): Int =
if (number != null) number*2 else 0
fun main() {
println(doubleSafe(null))
println(doubleSafe(4))
}
Result
0
8
이처럼 ? 을 이용하여 함수를 정의한다면 number
로 null이 입력 되면, 0을 return하게 된다.
2.3.2 Null Safe Operator (?.)
Java
if (str != null) str.length() else null
?.
을 Java로 표현하면 위와 같다.
이 문장을 Kotlin은 ‘?.
’ 단 두 문자로 해결한다.
아래는 ?.
을 응용한 Kotlin 함수이다.
Kotlin
fun strLen(str: String?): Int? = str?.length
fun main() {
println(strLen(null))
println(strLen("hello, blog!"))
}
Result
null
12
?.
연산자를 사용하면 str
이 null이 아니면 오른쪽의 함수를 수행하고, null이면 null을 반환한다.
str?.length() = null
일 수 있기 때문에 len: Int?
로 nullable 하게 선언 한 것이다.
여기서, str == null
이면 바로 null을 return한다는 점을 반드시 기억하자.
또한, property에 접근할 때도 ?.
을 사용할 수 있다.
Java
int double_major = if (student.majors.double_major != null) student.majors.double_major else null
Kotlin
val double_major = student.majors?.double_major
복수전공을 하는 학생일 경우 해당 과목 명을 가져오고, 아니라면 null이 된다.
데이터 형식은, 후술할 데이터 클래스 정의의 내용을 잠시 끌어와서 사용하였다.
2.3.3 Elvis Operator (?:)
고개를 좌로 90도 꺾고 바라보면 귀여운 캐릭터가 엘비스 프레슬리 머리를 하고있다.
그래서 Elvis operator이다!
?.
연산자는 좌항이 null일 때 null을 return 하지만,
?:
연산자는 좌항이 null이면 우항을 return한다.
Kotlin
fun doubleSafe(number: Int?): Int = (number ?: 0)*2
fun main() {
println(doubleSafe(null))
println(doubleSafe(4))
}
Result
0
8
Kotlin의 강력한 null 연산자를 잘 활용하면 이렇게 까지 함수를 압축할 수 있다!
아직은 처음이라 연산자들이 낯설고 헷갈리지만, 이 실용성에 익숙해지면 다시 자바로 돌아가기 싫을 것 같다.
2.4 데이터 클래스 정의, getter, settter
Java
public class Student {
private String name;
private String major;
private int age;
private int s_id;
public Student(String name, String major, int age, int s_id) {
this.name = name;
this.major = major;
this.age = age;
this.s_id = s_id
}
public String getName() {
return name;
}
public void setName(string name) {
this.name = name;
}
..... // 추가로 getter, setter, toString..
Kotlin
data class Student (var name:String, var major:String, var age:Int, var s_id:Int)
data로 class를 정의하여 생성자에 매개변수만 정의하면 getter, setter, toString 등 모두 사용 가능하다.
사용 예시
Java
Student student = new Student("Donggi Hong", "mathmatics", 23, 201421150);
String name = student.getName();
String major = student.getMajor();
int age = student.getAge();
student.toString();
Kotlin으로 작성한 데이터 형식이라도 Java에서 정상적으로 호환이 가능하다.
Kotlin
var student = Student("Donggi Hong", "mathmatics", 23, 201421150);
var name = student.name
var major = student.major
var age = student.age
student.toString()
2.5 Nested Class
Kotlin
data class Student (
var name:String,
var majors:Majors,
var age:Int,
var s_id:Int
){
data class Majors(
var major: String,
var double_major: String? = null,
var minor: String? = null
)
}
위 처럼 생성자 () 뒤에 {}을 붙이고, 그 안에 데이터 형식을 선언하면 끝이다.
중첩 클래스로의 접근은 다음과 같이 이루어진다.
var student = Student("Donggi Hong", Student.Majors("mathmatics","SW engineering", null), 23, 201421150);
var major = student.majors.major
var double_major = student.majors.double_major
var minor = student.majors.minor
2.6 String Interpolation
말이 장황하지만, 그냥 string에 변수 끼워넣는 것을 칭한다.
Kotlin
fun main() {
val str = "Blog!"
println("Hello, $str")
}
fun main() {
val str = "Blog!"
println("Hello, ${str}")
}
Result
Hello, Blog!
두 코드 모두 같은 실행 결과를 갖는다.
$
뒤에 한 개의 변수만 입력된다면, {}를 쓰지 않아도 되지만, 아래와 같이 2개 이상의 변수를 사용 할 예정이라면 반드시 사용하여야한다.
Kotlin
fun main() {
val str1 = "Hello, "
val str2 = "Blog!"
println("$str1+str2")
}
Result
Hello, +str2
Kotlin
fun main() {
val str1 = "Hello, "
val str2 = "Blog!"
println("${str1+str2}")
}
Result
Hello, Blog!
2.7 For문
Kotlin
fun main() {
val numbers = listOf('하나', 2, 'three', 4, '오')
for(number in numbers){
print("$number ")
}
}
Result
하나 2 three 4 오
Python의 for문과 비슷한 형태를 하고 있다.
Python은 for number in numbers
인 반면,
Kotlin은 for(number in numbers)
로, 괄호를 한번 더 사용하여야 한다.
index를 사용해 for문을 작동시키고 싶다면 다음과 같이 하면 된다.
Kotlin
fun main() {
val numbers = listOf("하나", 2, "three", 4, "오")
for(i in numbers.indices){
print("${numbers[i]} ")
}
}
Result
하나 2 three 4 오
list 자체를 이용한 for문과의 차이점이라면, numbers[i]를 반드시 {}로 묶어주어야 한다.
묶어주지 않으면 한번의 시행 마다 numbers 리스트를 출력하고, 뒤에 [i]라는 문자열을 붙여서 출력한다.
잘못된 예제는 다음과 같다.
Kotlin
fun main() {
val numbers = listOf("하나", 2, "three", 4, "오")
for(i in numbers.indices){
print("$numbers[i] ")
}
}
Result
[하나, 2, three, 4, 오][i] [하나, 2, three, 4, 오][i] [하나, 2, three, 4, 오][i] [하나, 2, three, 4, 오][i] [하나, 2, three, 4, 오][i]
2.8 When문
다른 언어의 switch문과 유사하다.
차이점은, 여러 타입을 사용하여도 알아서 컴파일러가 번역해서 잘 사용한다는 점이다.
Kotlin
fun checkNums(obj: Any) {
when (obj) {
"하나" -> println("$obj <- 이건 하나네!")
2 -> println("$obj <- 이건 둘이고,")
"three" -> println("$obj <- 얘는 세 번째.")
4 -> println("$obj <- 네번째는?")
else -> println("$obj <- 이건 모르겠다;;")
}
}
fun main() {
val numbers = listOf("하나", 2, "three", 4, "오")
for(number in numbers){
checkNums(number)
}
}
Result
하나 <- 이건 하나네!
2 <- 이건 둘이고,
three <- 얘는 세 번째.
4 <- 네번째는?
오 <- 이건 모르겠다;;
2.9 Collections
다른 언어처럼 List, Map, Set 등의 자료구조가 Kotlin에도 역시 존재한다.
listOf()
메소드를 사용해 배열을 선언하면 이는 변경할 수 없는 리스트가 된다.
대신, mutableListOf()
를 사용하여 배열을 선언하면 변경할 수 있는 리스트가 된다.
Kotlin
fun main() {
val numbers = mutableListOf("하나", 2, "three", 4, "오")
print("$numbers \n")
numbers.add("six")
print("$numbers \n")
numbers.remove("하나")
print(numbers)
}
Result
[하나, 2, three, 4, 오]
[하나, 2, three, 4, 오, six]
[2, three, 4, 오, six]
이런 식으로, 배열에 원소를 넣고 빼는 것이 가능하다.
이 뿐 아니라, filter, map 등을 사용해 배열을 관리할 수 있다.
Kotlin
fun main() {
val numbers = mutableListOf(1, 2, 3, 4, 5)
print(numbers.filter{it >= 3})
print("\n")
print(numbers.map{it * 2})
print("\n")
print(numbers.filter{it >= 3}.map{it * 2})
}
Result
[3, 4, 5]
[2, 4, 6, 8, 10]
[6, 8, 10]
it
대신에, num -> num
같은 형식으로 객체를 전달하여 사용 할 수도 있다.
🤟 Kotlin 답게 사용하자.
위 같은 강력하고 좋은 기술들을 두고 Java처럼 짜지 않도록 스스로 경계해야한다.
Kotlin은 Java의 대부분의 문법들을 사용할 수 있지만, 그보다 간결하고 직관적으로 코딩하는 방법이 여러가지 존재한다.
하지만 Java가 익숙한 사람이라면 자신도 모르게 Java에서 사용하던 문법을 언어만 바꿔서 그대로 사용하는 문제가 발생 할 것이다.
Kotlin을 앞으로 공부하며 한동안은 계속 사용하게 될텐데, 이런 오류에 빠지지 않도록 스스로 조심하며 코딩하도록 노력해야겠다.
댓글남기기