안드로이드 앱을 제작과정에 있는데
코틀린 언어에 대해 따로 작게라도 재정리를 해야 할 것 같아서 이 글을 씁니다.
자세히는 말고 개념만 잡자는 느낌으로 썼습니다.
* 이 글은 인프런 강의 <[입문편] 안드로이드를 위한 코틀린(Kotlin) 문법>을 보고 정리한 글입니다.
엘비스 연산자 (Elvis Operator)
fun main() {
println(findStringLength(null)) // 인자로 null 값
}
fun findStringLength(str : String?) : Int? { // 인자 값이 null일 수 있고, 반환 값이 null일 수 있음
return str?.length // 인자 값 str이 null일 수 있음
}
// 결과값은 null
'?' = null 일 수도 있다.
fun main() {
println(findStringLength(null)) // null 값의 길이는?
}
fun findStringLength(str : String?) : Int {
return str?.length ?: 0 // str이 null일 수 있는데, null이면 0으로 반환
}
'?:' = null 일 경우 값을 이렇게 하자.
Any / is / as
fun main() {
var str : Any = "abc" // Any = 어떤 자료형이든 포함
println(str) // 문자열(String) 출력
str = 123
println(str) // 숫자(Int) 출력
}
Any = 어떤 자료형이든 포함.
fun main() {
var str1 : Any = 123
if(str1 is String) {
println("this is string") // 자료형이 String이면 출력
} else {
println("this is not string") // 그렇지 않으면 출력
}
var str2 : Any = 123L // Long형 타입
when(str2) {
is Int -> {println("this is int")}
is String -> {println("this is string")}
else -> {
println("this is else") // Int, String이 아니므로 출력
}
}
is = 이 자료형입니까?
fun main() {
var str1 : String? = 1 as? String // String으로 변환 안되므로 null
println(str1) // null 출력
var str2 : String? = 1 as? String ?: "none" // null로 된다면 "none"으로
println(str2) // "none" 출력
}
as = 자료형 변환
as? = 자료형이 변환 안 되면 null로
List 가공
fun main() {
val testList = mutableListOf<Int>()
testList.add(1)
testList.add(2)
testList.add(3)
testList.add(4)
testList.add(10)
testList.add(10)
testList.add(11)
testList.add(11) // [1, 2, 3, 4, 10, 10, 11, 11]
println(testList.distinct()) // 중복제거 -> [1, 2, 3, 4, 10, 11]
println(testList.maxOrNull()) // 제일 큰 값 -> 11
println(testList.minOrNull()) // 제일 작은 값 -> 1
println(testList.average()) // 평균값 -> 6.5
}
.distinct() = 중복제거
.maxOrNull() = 제일 큰 값
.minOrNull() = 제일 작은 값
.average() = 평균값
fun main() {
val testList2 = listOf("john", "jay", "minsu", "minji", "viger")
val result1 = testList2.filter {
it.startsWith("m") // "m"으로 시작하는 값 필터
}
println(result1) // [minsu, minji]
val testList3 = listOf(1, 2, 3, 4, 5, 6)
val result2 = testList3.filter {
it % 2 == 0 // 2의 배수 필터
}
println(result2) // [2, 4, 6]
val testList4 = listOf("a", "aa", "aaa", "aaaa")
val result3 = testList4.groupBy {
it.length > 2 // 글자수가 2보다 큰 값은 true, 아니면 false 그룹
}
println(result3) // {false = [a, aa], true = [aaa, aaaa]}
println(result3[true]) // [aaa. aaaa]
}
.filter = 리스트 필터링 하겠음.
it = 리스트 안에 있는 값들
.startswith("m") = "m"으로 시작하는 값
.groupBy = 리스트 그룹핑 하겠음. (map 형식)
Class
fun main() {
InitialValue("kim_viger") // kim_viger와 기본값20 출력
InitialValue("viger", 30) // viger와 30 출력
}
class InitialValue(name: String, age : Int = 20) {
init { // 생성되면 자동으로 실행
println(name)
println(age)
}
}
클래스 = 설계 + 기능
init = 생성되면 자동으로 실행됨.
오버로딩
fun main() {
val c = Calculator()
c.sumNumber(1, 2) // 3
c.sumNumber(1, 2, 3) // 6
c.sumNumber("viger", "Happy") // vigerHappy
}
class Calculator() {
fun sumNumber(a : Int, b : Int) {
println(a + b)
}
fun sumNumber(a : Int, b : Int, c : Int) {
println(a + b + c)
}
fun sumNumber(str1 : String, str2 : String) {
println(str1 + str2)
}
}
오버로딩 = 겹겹이 쌓는다.
상속
fun main() {
Job() // "일을 합니다." 와 "마케팅을 합니다." 출력
}
open class AllJobs() { // 상속을 해주려면 open 키워드 쓰기
init {
println("일을 합니다.")
}
}
class Job() : AllJobs() { // ALLJobs()를 상속한다고 써주기
init {
println("마케팅을 합니다.")
}
}
open = 상속 가능한 클래스다.
상속하려면 상속할 클래스를 자료형처럼 써주기
상속과 오버라이딩
fun main() {
Child().doing() // "자식을 돌봅니다."
Child().disease() // "알러지가 있습니다."
}
open class Parents() { // 상속 가능
fun doing() {
println("자식을 돌봅니다.")
}
open fun disease() { // 오버라이드 가능
println("비염이 있습니다.")
}
}
class Child() : Parents() { // Parents 상속
override fun disease() { // 오버라이드 하겠다
// super.disease() // 그대로 사용
println("알러지가 있습니다.")
}
}
오버라이드 = 부모 클래스 메서드 재정의
open = 오버라이드 가능한 메서드다. (부모 클래스)
override = 부모 클래스의 메서드를 오버라이드 하겠다. (자식 클래스)
super = 그냥 부모 클래스대로 쓸게요.
추상 클래스
fun main() {
BMW().wheel() // "BMW 굴러갑니다."
BMW().engine() // "BMW 시동걸립니다."
}
abstract class Car { // 추상 클래스 선언
abstract fun wheel() // 추상 메서드 선언
abstract fun engine()
}
class BMW() : Car() { // 추상 클래스 Car 상속
override fun wheel() { // 추상 메서드 wheel() 오버라이드
println("BMW 굴러갑니다.")
}
override fun engine() { // 추상 메서드 engine() 오버라이드
println("BMW 시동걸립니다.")
}
}
abstract = 기존엔 비어있음. 상속/오버라이딩 때 꼭 채워야.
공통적인 기능을 구현하고 싶을 때 쓴다.
인터페이스
fun main() {
BMW().autoDriving() // "BMW 자율주행"
BMW().autoParking() // "BMW 자동주차"
}
abstract class Car {
abstract fun wheel()
abstract fun engine()
}
interface CarAutoDriving {
fun autoDriving()
}
interface CarAutoParking {
fun autoParking()
}
// 추상 클래스, 인터페이스 상속
class BMW() : Car(), CarAutoDriving, CarAutoParking {
override fun wheel() {
println("BMW 굴러감")
}
override fun engine() {
println("BMW 엔진시동")
}
// CarAutoDriving 인터페이스 메서드 채워넣기
override fun autoDriving() {
println("BMW 자율주행")
}
// CarAutoParking 인터페이스 메서드 채워넣기
override fun autoParking() {
println("BMW 자동주차")
}
}
인터페이스 = 기존에 비어있음. 상속 / 오버라이딩 되면 꼭 채워야.
추상 클래스보다 작은 단위 느낌.
데이터 클래스 (Data Class)
fun main() {
val justDog = JustDog("파트라슈", 12)
println(justDog.name)
println(justDog.age)
println(justDog.toString()) // JustDog@34c45dca 출력
val dataDog = DataDog("콜리", 15)
println(dataDog.name)
println(dataDog.age)
println(dataDog.toString()) // DataDog(name=콜리, age=15) 출력
val dataDog2 = dataDog.copy(name = "쉽독") // dataDog 복사. 이름만 변경
println(dataDog2.toString()) // DataDog(name=쉽독, age=15) 출력
}
class JustDog(var name: String, var age : Int)
data class DataDog(var name: String, var age : Int) // 데이터 클래스
데이터 클래스 = 데이터 받은 것을 서버에 넣어 놓을 때 사용
중첩 클래스 (Nested class), 내부 클래스 (Inner class)
fun main() {
val test1 = Test1.TestNestedClass()
test1.testFun1()
val test2 = Test2().Test2InnerClass()
test2.testFun2()
}
class Test1 {
val tempText1 = "tempText1"
class TestNestedClass {
fun testFun1() {
println("TestFun1")
println(tempText1) // 에러
}
}
}
class Test2 {
val tempText2 = "tempText2"
inner class Test2InnerClass {
fun testFun2() {
println("TestFun2")
println(tempText2) // 출력됨
}
}
}
중첩 클래스 = 클래스 안에 클래스 중첩. (클래스 바깥 변수 사용 X)
내부 클래스 = 클래스 안에 속 클래스. (클래스 바깥 변수 사용 O)
중첩 클래스 -> 객체지향 / 캡슐화
내부 클래스 -> RecyclerView