본문 바로가기
Study/APP

Kotlin 고급 문법

1. 람다

파이썬과 js에서 좀 봤던 친구가 나온다. 알고리즘 문제를 풀 때 모를 때마다 찾아봤던 친군데, 객체지향 성격을 띠는 코틀린에서 함수형 프로그래밍의 큰 장점인 람다가 있다는 게 신기했다. 우선 람다의 유용한 점을 살펴보자. 첫 번째로, 매소드의 파라미터로 함수를 넘겨줄 수 있다. 두 번째는 파라미터뿐만 아니라 return값에도 함수처럼 넘겨줄 수 있다. 람다의 기본형식은 다음과 같다.

 

val lambdaname : Type {argumentlist -> codeBody}

 

위와 같은 형태로 적어주면 된다. 쉽게 말해서 람다로 계산하고 싶은 변수를 argumentlist에 넣어주고, 계산 식, 리턴 값을 codeBody에 넣어주면 람다식을 완성할 수 있다. 

람다식을 위와 같이 작성해 보았다. 둘의 다른 점은 타입 추론을 어느 부분에 적어놨는지이다. 첫 번째 코드는 변수를 설정하는 부분에서 바로 타입이 추론되게 적어줬고, 밑에 코드는 codeBody 부분에 타입을 적어줘 타입 추론이 가능하게 해 줬다. 확장 함수로 사용할 때에도 람다가 유용하게 쓰인다. 

확장하기 위해 위와 같이 람다식을 적어주자. 여기서 this는 String.()에서 오는 문자열을 적어준 것이다. 

그리고 위와 같이 문자열을 변수로 설정한 뒤 문자열. pizza()를 적어주면 위의 String 확장과 합해져서 문자열이 출력된다. 

이렇게 함수 안에 람다식을 넣어줘서 문자열을 출력할 수도 있는데, 위의 방법이 조금 더 편한 것 같다. 그리고 람다로 return을 해야 하는 일이 생기면 항상 return 되는 변수에 맞게 정확하게 return을 해줘야 한다. 

위와 같이 람다로 return값이 있는 경우에는 it에 어떠한 integer 숫자가 들어올 수 있으므로, 지정 범위 외에 들어올 수 있는 다른 범위도 처리를 해줘야 한다. 이제 람다를 함수 파라미터에 넣어보는 방법을 알아보자.

invokelambda 함수 파라미터 안에 람다를 설정해주자. 

그리고는 변수를 람다식으로 설정해주고, 함수 안에 람다를 집어넣으면 된다. 조금 복잡하다. 이 부분에 대해서 배우면서 굳이 이렇게 짜야하는 코드가 있을까?라는 생각을 잠시 해봤다. 뭐 공부하다가 나오면 나온 예시를 바탕으로 조금 더 깊게 공부해보자는 마인드로 람다 리터럴을 살펴봤다. 

람다 리터럴은 어렵지 않다. 그냥 변수를 설정해주고 그 변수를 파라미터로 활용한 람다식에 변수를 설정해주지 않고, it을 활용해 파라미터에 넣어주는 방식이다. 함수의 마지막 파라미터가 람다라면 소괄호를 지우고 위의 식을 완성해도 된다. 

 

2.Data class

말 그대로 데이터를 담는 클래스이다. array라고 봐도 편하다. 일반 class와는 다르게 객체를 프린트하면 메모리의 주소를 보여주는 것이 아니라, 바로 데이터를 print 하게 해 준다. 

위와 같이 사용이 가능하다. 

3.Companion Object

자바의 static대신에 사용된다. 정적 메서드 대신 사용한다고 보면 된다. 코틀린에서는 static이라는 키워드가 없다. 하지만, 어플을 만들다 보면 정적 메서드가 필요할 때가 있다.

  • 액티비티/프래그먼트의 인텐트 Extra로 사용하는 키
  • 로그 출력을 위한 태그(Tag) 이름 정의
  • 뷰 내부에서 사용하는 고정된 길이 값 (너비, 높이 등)
  • 각종 유틸리티 클래스 내 메서드

위의 예시들에서는 정적 메서드가 필요하다. 그래서 코틀린에 Companion Object가 있다. 엄연히 말하면 Companion Object는 static이 아니다. 객체이다.

원래라면 생성자를 제외하고, class를 선언한 뒤 이 class를 객체로 만들어서 사용하려면, Main함수에서 새롭게 변수를 정의해준 뒤 객체를 설정하고 class안에 있는 property와 함수를 사용해줘야 한다. 하지만, 그럴 필요 없이 바로 객체로 만들어서 사용해야 하는 경우가 위와 같이 있을 수 있다. 

그럴 경우에 위와 같이 class 안에 companion object를 사용하면 클래스가 메모리에 적재되면서 property들도 같이 적재되기 때문에 따로 객체 생성 없이 property들을 사용해 줄 수 있다. 

Companion object는 객체이기 때문에 위와 같이 변수로 설정해주고 객체를 만들어준 다음에 객체 안에 있는 property들을 사용할 수 있다. 당연한 것이겠지만 companion object는 class내에서 딱 한 번만 사용할 수 있다. 여러 번 사용하면 메모리에 적재될 때 당연히 충돌이 나기 때문에 참조하는 값이 여러 개가 생겨버리는 일이 발생하게 되기 때문이다. 인터페이스 내에도 companion object를 사용할 수 있다. 

 

4.중첩 클래스(nested class) / 내부 클래스(inner class)

중첩 클래스와 내부 클래스의 공통점은 클래스 안에 한번 더 정의된다는 것이다. 여기서 inner를 쓰면 내부 클래스, 그냥 class를 정의하면 중첩 클래스가 된다. 사실 중첩 클래스는 말만 중첩이지 외부 클래스와 전혀 연관이 없다. 외부 클래스에 변수를 설정했다고, 중첩 클래스 안에 그 변수를 사용하면 안 된다는 뜻이다.

중첩 클래스에서 외부 클래스의 변수를 사용하려면 위와 같이 빨간색으로 error가 난다. 

하지만 inner class, 내부 클래스는 오류가 나지 않는다. 외부 클래스를 참조할 수 있다는 말이다. 이를 보면 알 수 있듯이 내부 클래스는 외부 클래스의 인스턴스의 참조를 물고 탄생한다. 그래서 class 내부에 따로 정의하는 것이 아니라 바깥에서 정의를 해주려면 반드시 클래스 이름 뒤에 인스턴스()를 포함하고. innercase로 생성을 해줘야 한다. 중첩 클래스와 내부 클래스에 private과 같은 접근 제한자를 붙여줄 수 있다. 접근 제한자를 붙이면 내부 클래스의 인스턴스를 외부로 공개하지 않게 한다. 사실 이 부분이 메모리 관리 측면에서는 효율적일 수도 있다. 하지만 내부 클래스는 private을 붙여 선언하는 게 효율적이지 않을 수 있다. 내부 클래스는 만드는 시점부터 자연스럽게 외부 클래스와 자원을 공유한다. 그렇지 않으면 내부 클래스를 만드는 의미가 없다. 그렇기 때문에 private을 붙여서 접근 제한을 할 경우에는 효용 가치가 많이 떨어질 수 있다. 또한 자바에서도 내부 클래스에는 static이 금지된 것을 배웠다. 코틀린도 마찬가지이다. 중첩 클래스에서는 companion object가 허락이 되지만, 외부 클래스와 메모리를 공우하는 내부 클래스는 companion object가 허락되지 않는다. 내부 클래스에서 companion object를 써버리면 메모리가 적재될 때 내부 클래스만 같이 적재할지, 클래스를 감싸는 외부 클래스까지 같이 올릴지 모호해지기 때문이다. 그래서 내부 클래스에는 companion object 사용이 금지되어 있다. 

5.Object

클래스를 생성함과 동시에 객체를 생성할 수 있는 class이다. Single Pattern을 구현할 수 있는 것이다. 또한, 익명 클래스를 생성해 줄 수 있으므로 이 두 개 중에 하나를 하고 싶다면 Object로 class를 만들어줘야 한다.

'Study > APP' 카테고리의 다른 글

[디자인 패턴] MVVM  (0) 2022.09.14
Kotlin 기본 문법  (0) 2021.12.07