이전까지는 코틀린의 기본 문법을 배웠고, 이제는 심화 부분을 정리하고자 한다.
접근제한자는 변수나 메소드의 접근을 제한할 수 있는데, 코틀린에서는 다른 언어들과 동일하게 public, private, internal, protected 로 객체를 이용해서 변수나 메소드를 호출할 수 있는 여부(접근)를 결정한다.
public: 어디서나 접근 가능 (명시하지 않으면 기본적으로 public 사용)private: 동일한 클래스 내부에서만 접근 가능interval: 같은 모듈 내부에서만 접근 가능protected: 기본적으로는 private이지만, 상속을 받은 경우 다른 모듈에서 접근 가능
👉 정리하자면 public, 상속받은 경우 protected는 다른 모듈에서 접근이 가능하다.
접근 제한자를 사용하면 접근 권한을 통해 데이터에 무분별한 접근을 막을 수 있으며, 유지보수도 간편하다.
클래스를 만들 떄 초기의 값을 정의하기 어려워서 나중에 대입하기 위한 것으로 변수나 상수의 값을 나중에 초기화할 수 있고, 코틀린은 자연초기화나 늦은초기화를 사용할 따는 lateinit과 lazy 키워드를 사용해야 한다.
(1) 변수의 지연초기화
변수 값을 초기에 정의하기 어려울 때 lateInit을 사용하는 것이 기본적이다.
변수 사용 전에 초기화 되었는지 확인해 안정성 높이기
isInitialized를 활용해서 값이 초기화되었는지 (true/false)로 확인
사용할 때는 값이 아니라 참조 형태로 사용해야 하므로 this:: 또는 ::를 붙이기
(2) 상수의 지연초기화
상수의 지연초기화는 lazy 키워드를 활용해서 지연초기화를 수행하는데, 상수를 사용하는 시점에 값을 대입하고 초기화가 수행된다.
가장 궁극적인 이유로는 저사양으로 제한되어있는 환경에서는 메모리를 더욱 효율적으로 사용할 수 있기 떄문에 지연초기화를 사용해야 한다 !!
가장 중요한 내용!
코틀린의 NULL 안정성을 향상시키기 위해 사용하는 Null Safety. 근데 이 NULL 안정성, 왜 향상시켜야 할까? NULL 예외는 프로그램의 기용성을 저하시키는 치명적인 오류이기 때문이다. 프로그램이 강제로 종료되는 현상이 발생해버리는...😒 코틀린은 자료형에 NULL 여부를 명시해 NULL 예외로부터 안전하게 설계가 가능하다.
? , !!, ?. , ?: 의 키워드를 사용해 NULL 예외에서 벗어날 수 있지만, 강제로 NULL이 아니라고 하는 !!는 사용을 자제하는 것이 좋다.
fun main() {
var s = Student()
s.name = "다민"
s.displayAdressLength()
s.adress = "서울"
s.displayInfo()
}
class Student {
lateinit var name::String
var adress:String? = null
fun displayInfo() {
println("이름 : ${name}")
println("주소 : ${adress}")
}
fun displayAdressLength() {
println("주소의 길이 : ${adress?.Length}")
}
}
위의 예시로 다시 정리해보자. 주소를 저장하는 address는 초기값이 null이기 떄문에 null 위협에 있기 떄문에 Null이 아님을 보장해야 한다. 그런데 여기서 !!를 사용하는 것보다 ?. 키워드로 null인지 확인하고 null이 아닐 경우에만 참조하는 메소드를 실행해야 한다.
// main은 위의 예시와 동일
class Student {
lateinit var name::String
var adress:String? = null
fun displayInfo() {
println("이름 : ${name}")
println("주소 : ${adress}")
}
// 길이가 NULL일 경우 "초기화하기"라는 문자열 출력
fun displayAdressLength() {
println("주소의 길이 : ${adress?.Length ?: "초기화하기"}")
}
}
배열은 변수를 순서를 매겨서 활용할 수 있고 일반적으로 변수를 선언하면 변수의 위치정보가 연속적이지 않기 때문에 순서 없이, 랜덤으로 생성된다. 이때, 배열을 통해 변수에 순서를 매겨서 연속적으로 활용이 가능하고, 코틀린에서는 배열을 사용할 때는 arrayOf 메소드 라는 키워드를 사용하면 된다.
// 배열 사용 예시
var arr = arrayOf(1, 2, 3)
println(Arrays.toString(arr))
컬렉션은 개발에 유용한 리스트, 맵, 집합 자료구조를 제공해준다. 리스트는 읽기전용과 수정 가능한 종류로 구분할 수 있으며, 배열과 달리 정해진 크기가 없어 독적으로 값을 추가할 수 있다.
- List
읽기 전용 리스트는ListOf키워드 사용, 수정 가능한 리스트는mutableListOf키워드 사용
// 읽기 전용 리스트
var score1 = ListOf(값1, 값2, 값3)
// 수정 가능 리스트 1
var score2 = mutableListOf(값1, 값2, 값3)
score2.set(인덱스, 값)
// 수정 가능 리스트 2
var score3 = ArrayList<자료형>(값1, 값2, 값3)
score3.set(인덱스, 값)
- Map (쌍으로 이루어진 자료형)
맵은변수명[키]로 데이터에 접근이 가능하다.
읽기 전용 맵은mapOf키워드 사용, 수정 가능 맵은mutablemapOf키워드 사용
// 읽기 전용 맵
var scoreInfo1 = mapOf("kor" to 95, "math" to 90, "eng" to 80)
println(scoreInfo1("kor"))
// 수정가능 맵
var scoreInfo2 = mutablemapOf("kor" to 96, "math" to 90)
scoreInfo("eng") = 80 // eng 추가
println(scoreInfo2("eng"))
// 맵 키와 값을 동시에 추출 후 사용 가능
for((k, v) in scoreInfo2) {
println("${k}의 값 : ${v}")
- Set
순서가 존재하지 않고 중복없이 데이터를 관리할 수 있는 집합(교집합, 합집합, 차집합) 자료형으로 다른 컬렉션들은 요소를 찾는 것에 집중하지만, Set은 요소의 존재여부에 집중한다. 읽기 전용 Set은setOf키워드를 사용하고 수정 가능 Set은mutableSetOf키워드 사용
// 읽기 전용 Set
var birdSet = setOf("참새", "까마귀", "박새")
// 수정 가능 Set
var mutableBirdSet = mutableSetOf("참새", "까마귀", "박새")
mutableBirdSet.add("닭")
// 집합 예시
// 귀여운 새들
var bird = SetOf("참새", "까마귀", "앵무새", "병아리")
// 날 수 있는 새들
var flybird = SetOf("참새", "까마귀", "박새", "앵무새", "까치")
// 모든 새들의 집합 (합집합)
var unionBird = bird.union(flybird)
// 귀엽고 날 수 있는 새들의 집합 (교집합)
var intersectBird = bird.intersect(flybird)
// 귀여운 새들 중에서 날 수 없는 새들의 조합 (차집합)
var substractBird = bird.substract(flybird)
각각의 객체는 다른 위치정보를 가지고 있어서 저장하는 값도 객체마다 고유의 값을 가지고 있는데, 싱클턴을 활용하면 해당 객체는 메모리 전역에서 유일함을 보장하고 위치정보가 고정이 도기 떄문에 메모리 전역에서 유일한 객체임을 보장할 수 있다.
companion, object 키워드로 싱글턴을 구현할 수 있다 !
// 객체 생성 없이도 클래스 정보에 접근 가능 (생성자 호출 X)
fun main() {
Bird.fly("참새")
}
Object Bird {
fun fly(name::String) {
println("${name}가 날아요 !")
}
}
👉참고 : 생성자 호출 유무와 관계없이 객체를 생성하지 않고도 클래스 정보에 접근이 가능하다!
예외처리는 프로그램 실행 도중에 발생하는 런타임 에러 예외를 적절히 처리할 때 필요하다.
try - catch와 throw로 예외를 처리한다.
에러로 인해 프로그램이 도중에 실행이 종료되는 것을 막기 위해 즉, 미리 예외를 생각하고 코드를 작성해 프로그램의 안정성을 높이기 위해 사용한다.
(1) try - catch의 구조
fun method() {
try {
에러 발생 가능성이 존재하는 코드 입력
} catch(예외종류) {
에러가 발생했을 때 처리할 코드
}
}
(2) throw 구조
fun method(num1:Int) { if(num1 - 10) { throw 예외종류 } }
👉예외를 던지기만 : throw
👉예외를 던지고 이 예외가 발생했을 때 처리해라 : try - catch
아주 중요한 정보를 얻었습니다, 감사합니다.