[Kotlin] 코틀린 함수 정리

그때그때 모르는 함수 있으면 정리해서 올리는 용도

목차

when
Callback
Data Class
lateinit, lazy
public, private, internal, protected
Generic Type
Let

1. when

  • 일반 C같은 곳에서 사용되던 Switch문을 대체함
1
2
3
4
5
6
7
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> {
print("x is neither 1 nor 2")
}
}
  • 보통 Switch의 default는 필수가 아니지만 Kotlin의 When은 else문이 필수로 들어가야 한다.
  • 많은 경우가 동시에 처리되야하면 콤마를 사용한다
1
2
3
4
when (x) {
0, 1 -> print("x == 0 or x == 1")
else -> print("otherwise")
}
  • 각 조건에 상수가 아닌 함수가 올 수도 있다
1
2
3
4
when (x) {
parseInt(s) -> print("s encodes x")
else -> print("s does not encode x")
}
  • in을 사용하면 범위를 지정할 수 있다.
1
2
3
4
5
when (x) {
in 1..10 -> print("x is in the range")
in validNumbers -> print("x is valid")
!in 10..20 -> print("x is outside the range")
else -> print("none of the above")
  • 인수를 생략해서 사용도 가능하다. 이 경우 해당 조건이 참일 경우에만 분기문이 실행된다.
1
2
3
4
5
when {
x.isOdd() -> print("x is odd")
x.isEven() -> print("x is even")
else -> print("x is funny")
}

2. callback

콜백함수는 늘 봐도봐도 헷갈린다.

코틀린에서 콜백함수를 만들고 사용하는 법을 정리한다.

  • 사용법
    1
    2
    3
    fun [함수명] (callback: ([변수 자료형]) -> Unit) {
    callback(변수명)
    }

콜백함수 문법은 특정 함수의 동작이 끝남과 동시에, 다른 여러 가지 함수를 호출해야 할 경우에 사용된다.

Unit 형으로 변수가 Return 되어 다시 위에 선언한 변수의 자료형으로 변환된다.
쓰다보면 다중으로 콜백을 해야하는 상황이 생기는데, 이런 경우를 없애는 방법을 찾고싶다.

3. data class

코틀린에서 data Class를 이용하면 자바에서 만들어야했던

GET, SET, ToString, Copy

등의 간단한 함수들을 자동으로 구현해준다.

  • 사용법
    1
    2
    3
    4
    5
    6
    7
    8
    data class LecturesResponseModel(

    val lectures: List<LecturesModel>? = null,

    val count: Int? = null,

    val scannedCount: Int? = null
    )

주로 Model들의 정의를 할 때 사용한다.
소괄호로 이루어져있으므로 쉼표를 붙이며 주의해서 사용해야 한다.

4. lateinit, lazy

  • lateinit

  • 프로퍼티의 초기화를 나중에 하기 위한 키워드이다.

  • 반드시 null이 아닌 변수가 생성당시가 아닌 나중에 초기화를 해야할 때 사용한다.

  • 제약사항

    • var(mutable) 프로퍼티만 사용 가능
    • non-null 프로퍼티만 사용 가능
    • 커스텀 getter/setter가 없는 프로퍼티만 사용 가능
    • primitive type 프로퍼티는 사용 불가능
    • 클래스 생성자에서 사용 불가능
    • 로컬 변수로 사용 불가능
  • DI에서 사용하는 경우

    1
    2
    @Inject
    lateinit var presenter: SimpleSignInPresenter
  • DI를 통해 SimpleSignInPresenter를 외부에서 주입받기 때문에
    별도로 해당 프로퍼티에 명시적으로 null을 대입하지 않는 이상
    Non-null이라고 확신할 수 있다.

  • lazy

  • 프로퍼티의 초기화를 나중에 하기 위한 함수이다.

  • lateinitModifier이지만 lazy
    람다를 파라미터로 받고 Lazy<T> 인스턴스를 반환하는 함수다.

  • 제약사항

    • val(immutable) 프로퍼티만 사용 가능
    • primitive type 에도 사용 가능
    • 커스텀 getter/setter가 없는 프로퍼티만 사용 가능
    • Non-null, Nullable 둘다 사용 가능
    • 클래스 생성자에서 사용 불가능
    • 로컬 변수에서 사용 가능
  • 사용법

    1
    private val toolbar by lazy { home_toolbar }
  • lazy 프로퍼티 연산은 기본적으로 동기화된다.

    • Thread-safe 하다
    • 기본적으로 UNINITIALIZED_VALUE 로 초기화되고 value 호출이 일어날 때 다시 초기화된다.
  • lazy 를 사용하면 activity가 올라온 후에 초기화 할 수 있다.

5. public, private, internal, protected

  • 가시성 제한자이다.
  • kotlin 은 명시적으로 제한자를 지정하지 않으면 public 가시성을 갖는다.
  • 패키지 레벨에서 가시성 제한자에 따른 접근 범위
    • public : 모든 곳에서 해당 선언에 접근할 수 있다.
    • private : 해당 선언을 포함한 파일 내에서만 접근할 수 있다.
    • internal : 같은 모듈 안에서 접근할 수 있다.
    • protected : 최상위 레벨 선언에서는 protected를 사용할 수 없다.
      1
      2
      3
      4
      5
      6
      7
      8
      package foo

      private fun foo() {} // example.kt에서만 접근 가능

      public var bar: Int = 5 // 프로퍼티는 모든 곳에서 접근 가능
      private set // setter는 example.kt에서만 접근 가능

      internal val baz = 6 // 같은 모듈 안에서 접근 가능
  • 클래스, 인터페이스 레벨에서 가시성 제한자에 따른 접근 범위
    • public : 선언한 클래스에 접근할 수 있는 모든 클라이언트가 public 멤버에 접근 가능하다.
    • private : (클래스의 모든 멤버를 포함한) 클래스 안에서만 접근 가능하다.
    • internal : 선언한 클래스에 접근할 수 있는 모듈에 속한 클라이언트가 internal 멤버에 접근 가능하다.
    • protected : private과 동일하지만 + 하위 클래스에서 접근 가능하다.
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23

      open class Outer {
      private val a = 1
      protected val b = 2
      internal val c = 3
      val d = 4 // 기본으로 public

      protected class Nested {
      public val e: Int = 5
      }
      }

      class Subclass : Outer() {
      // a에 접근 불가
      //b,c 그리고 d에 접근 가능
      // Nested와 e에 접근 가능
      }

      class Unrelated(o: Outer) {
      // o.a, o.b에 접근 불가
      // o.c(같은 모듈)와 o.d에 접근 가능
      // Outer.Nested에 접근 불가, 그리고 Nested::e에도 접근 불가
      }

6. generic type

  • 제네릭 타입은 Type 을 Parameter 로 가지는 Class 나 Interface 를 말함
  • 클래스 또는 인터페이스 이름 뒤에 <> 부호가 붙고 사이에 타입 파라미터가 위치함
  • 제네릭을 왜 쓰는가?
    • 컴파일 시 강한 Type Check 를 할수 있다.
    • 타입 변환 (Casting) 을 제거한다.
1
2
3
4
5
6
7
8
9
10
List list = new ArrayList();
list.add("hello");

String str = (String) list.get(0); // 타입 변환이 필요
--------------------------------------------------------------------

List<String> list2 = new ArrayList<>();
list2.add("hello");

String str2 = list.get(0); // 불필요
  • 타입 파라미터는 일반적으로 대문자 알파벳 한 글자로 표현한다.

    1
    2
    3
    public class 클래스<T> { ... }

    public interface 인터페이스<T> { ... }
  • 제네릭 타입은 두 개 이상의 멀티 파라미터를 이용할 수 있다. 이 경우 각 타입 파라미터는 콤마로 구분한다.

  • 제네릭 메소드
    • 제네릭 메소드는 매개변수와 반환자료형의 Type 이 Type Parameter 를 갖는 메소드를 뜻함
    • public <T> [리턴Type] [메소드명] () {} 이와같이 선언함
    • 객체.<T>함수명 이와같이 사용도 가능함. 함수의 리턴 타입을 명시하는 용도

7. Let

  • Let 함수를 호출하는 객체를 block 부분의 인자로 넘긴다.
  • block 의 결과를 반환한다.

inline fun <T, R> T.let(block: (T) -> R) : R

  • 사용 예시
    • 널 체크후 코드 실행하고 싶을 경우
    • 블록 내의 결과물을 반환하고 싶을 경우
    • 단일 지역 변수의 범위를 제한하고 싶을 경우
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Test
fun blockTest() {
val person = Person("park", "jieun")

val result = person?.let {
printPerson(it.lastName + it.firstName)
}
Assert.assertEquals(result, "parkjieun")
}

private fun printPerson(msg: String): String {
println(msg)
return msg
}
공유하기