함수 정의와 호출 1

코틀린에서 컬렉션 만들기

코틀린에서는 코틀린만의 컬렉션을 만들지 않고 모두 자바의 컬렉션은 그대로 사용하고 추가적인 함수를 제공하고 있다. 컬렉션을 만들 때엔 대체적으로 컬렉션명 + Of의 조합이다.

1
2
3
4
5
6
7
8
9
10
val set = hashSetOf(1, 7, 53)
val list = arrayListOf(1, 7, 53)
val map = hashMapOf(1 to "one", 7 to "seven", 53 to "fifty-three")

>>> println(set.javaClass)
class java.util.HashSet
>>> println(list.javaClass)
class java.util.ArrayList
>>> println(map.javaClass)
class java.util.HashMap

이름 붙인 인자

최신의 몇몇 언어들은 함수에 전달하는 인자의 이름을 명시할 수 있도록 지원하고 있다. 코틀린 역시 마찬가지다.

1
2
fun joinToString(collection: Collection<T>, separator: String, prefix: String, postfix: String)
joinToString(collection, separator = " ", prefix = " ", postfix = ".")

단 호출 시 인자 중 어느 하나라도 이름을 명시하고 나면 혼동을 막기 위해 그 뒤에 오는 모든 인자는 이름을 꼭 명시해야 한다.

디폴트 파라미터

CPP를 했던 사람에게 자바를 할 때 불편했던 점 한가지를 들자면 대부분 디폴트 파라미터 얘기가 나온다. 디폴트 파라미터는 함수의 파라미터에 기본 값을 설정 해줄 수 있는데 이렇게 되면 불필요한 함수 오버로딩을 줄일 수 있기 때문에 유용하게 사용하게 된다. 코틀린에서는 이와같이 유용하게 사용할 수 있는 디폴트 파라미터를 적용했다. 그리고 이름 붙인 인자와 같이 사용하게 되면 효용성은 더 높아진다.

1
2
3
4
5
6
7
8
9
10
fun joinToString(
collection: Collection<T>,
separator: String = ", ",
prefix: String = "",
postfix: String = ""
): String

>>> joinToString(collection)
>>> joinToString(collection, "; ")
>>> joinToString(collection, postfix = ";", prefix = "# ")

만약 자바에서 코틀린 함수를 호출할 때 디폴트 파라미터로 구현돼 있을 경우 코틀린 함수에 @JvmOverloads애노테이션을 추가하면 자동으로 함수 오버로딩을 작성해준다.

1
2
3
4
5
// java
String joinToString(Collection<T> collection, String separator, String prefix, String postfix);
String joinToString(Collection<T> collection, String separator, String prefix);
String joinToString(Collection<T> collection, String separator);
String joinToString(Collection<T> collection);

최상위 함수

코틀린의 함수는 최상위 레벨이다. 자바에서는 클래스가 최상위 레벨이므로 모든 함수는 클래스 내부에 포함되어야 했다. 그렇기 때문에 공통 함수들을 포함하는 클래스들을 매번 생성해줘야 하므로 불필요한 클래스가 만들어졌다. 코틀린은 앞서 설명했든 함수가 최상위 레벨이므로 클래스를 만들지 않고 원하는 파일에 작성하면 된다.

1
2
3
4
5
6
7
8
9
10
// kotlin, join.kt 파일
package strings
fun joinToString(...): String { ... }


// java
package strings
public class JoinKt {
public static String joinToString(...) { ... }
}

코틀린에서 작성한 함수는 자바로 변경될 때 파일명이 클래스가 되며 그 안에 함수를 포함시킨다. 만약 파일명이 클래스명으로 사용되기 싫다면 @JvmName 애노테이션을 해당 파일의 제일 앞(package보다)에 위치하면 된다.

확장 함수

코틀린에서 제공하는 개념으로 확장 함수는 어떤 클래스의 멤버 메소드인 것처럼 호출할 수 있지만 그 클래스의 밖에 선언된 함수다. 아래의 예를 보면 쉽게 이해할 수 있다.

1
2
3
4
5
package strings
fun String.lastChar(): Char = this.get(this.length - 1)

// this 생략
fun String.lastChar(): Char = get(length - 1)

이 예는 문자열의 마지막 문자를 돌려주는 메소드이다. 실제로 String 클래스에는 lastChar가 없다. 하지만 마치 String의 멤버 함수인 것처럼 다른 곳에서 lastChar 함수를 사용할 수 있다.

확장 함수를 만들려면 추가하려는 함수 이름 앞에 그 함수가 확장할 클래스의 이름을 덧붙이기만 하면 된다. 클래스 이름을 수신 객체 타입이라 부르며, 확장 함수가 호출되는 대상이 되는 값을 수신 객체라고 부른다. 위 예제에서는 String이 수신 객체 타입이며 this가 수신 객체이다. 또한 확장 함수는 클래스의 캡슐화를 깨지 않도록 private, protected멤버는 사용할 수 없다.

그리고 확장 함수는 수신 객체의 멤버 함수보다 레벨이 낮다. 수신 객체의 멤버 함수와 이름이 동일할 때 확장 함수가 아닌 멤버 함수가 호출된다. 그러므로 확장 함수를 만들 때엔 항상 클래스의 API를 염두 해 둬야 한다.

자바에서 확장 함수 호출

내부적으로 확장 함수는 수신 객체를 첫 번째 인자로 받는 정적 메소드다. 그래서 확장 함수를 호출해도 다른 어댑터 객체나 실행 시점 부가 비용이 들지 않는다. 확장 함수도 일반 함수와 마찬가지로 자바에서 호출 시 파일 이름에 따라 결정된다. 따라서 확장 함수를 StringUtil.kt 파일에 정의했다면 다음과 같이 호출할 수 있다.

1
2
// java
char c = StringUtilsKt.lastChar("java")

출처 : Kotlin in Acation

#

댓글

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×