> [1,2,3] ``` - 디폴드 구현과 달리 (1;2;3) 처럼 원소"> > [1,2,3] ``` - 디폴드 구현과 달리 (1;2;3) 처럼 원소"> > [1,2,3] ``` - 디폴드 구현과 달리 (1;2;3) 처럼 원소">
# 3장 함수 정의와 호출
### 이번장에서는...
#### 배운점, 느낀점
1. 컬렉션, 문자열, 정규식을 다루기 위한 함수
2. 이름을 붙인 인자, 디폴트 파라미터 값, 중위 호출 문법 사용
3. 확장 함수와 확장 프로퍼티를 사용해 자바 라이브러리 적용
4. 최상위 및 로컬 함수와 프로퍼티를 사용해 코드 구조화
---
### 코틀린에서 컬렉션 만들기
```kotlin
package part3
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") // to가 언어가 제공하는 특별한 키워드가 아니라 일반 함수라는 점에 유의
val strings = listOf("first", "second", "fourteenth")
fun main() {
println(set.javaClass)
println(list.javaClass)
println(map.javaClass)
println(strings.last())
println(set.max())
}
val list = listOf(1, 2, 3)
println(list)
// >> [1,2,3]
package part3
import java.lang.StringBuilder
fun <T> joinToString( // 이 함수는 제네릭 하다 즉, 이 함수는 어떤 타입의 값을 원소로 하는 컬렉션이든 처리할 수 있다.
collection: Collection<T>,
separator: String,
prefix: String,
postfix: String
): String {
val result = StringBuilder(prefix)
for ((index, element) in collection.withIndex()) {
if (index > 0) result.append(separator) // 첫 원소 앞에는 구분자를 붙이면 안 된다.
result.append(element)
}
result.append(postfix)
return result.toString()
}
fun main() {
val list = listOf(1, 2, 3)
println(joinToString(list, ";", "(", ")"))
}
fun main() {
val list = listOf(1, 2, 3)
println(joinToString(collection = list, separator = ";", prefix = "(", postfix = ")"))
}
fun <T> joinToString( // 이 함수는 제네릭 하다 즉, 이 함수는 어떤 타입의 값을 원소로 하는 컬렉션이든 처리할 수 있다.
collection: Collection<T>,
separator: String = ",",
prefix: String = "",
postfix: String = ""
): String
package part3;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import kotlin.Metadata;
import kotlin.collections.CollectionsKt;
import kotlin.jvm.JvmOverloads;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
@Metadata(
mv = {1, 7, 1},
k = 2,
d1 = {"\\u0000\\u0018\\n\\u0000\\n\\u0002\\u0010\\u000e\\n\\u0002\\b\\u0002\\n\\u0002\\u0010\\u001e\\n\\u0002\\b\\u0004\\n\\u0002\\u0010\\u0002\\n\\u0000\\u001a:\\u0010\\u0000\\u001a\\u00020\\u0001\\"\\u0004\\b\\u0000\\u0010\\u00022\\f\\u0010\\u0003\\u001a\\b\\u0012\\u0004\\u0012\\u0002H\\u00020\\u00042\\b\\b\\u0002\\u0010\\u0005\\u001a\\u00020\\u00012\\b\\b\\u0002\\u0010\\u0006\\u001a\\u00020\\u00012\\b\\b\\u0002\\u0010\\u0007\\u001a\\u00020\\u0001H\\u0007\\u001a\\u0006\\u0010\\b\\u001a\\u00020\\t¨\\u0006\\n"},
d2 = {"joinToString", "", "T", "collection", "", "separator", "prefix", "postfix", "main", "", "playground.main"}
)
public final class TwoKt {
@JvmOverloads
@NotNull
public static final String joinToString(@NotNull Collection collection, @NotNull String separator, @NotNull String prefix, @NotNull String postfix) {
Intrinsics.checkNotNullParameter(collection, "collection");
Intrinsics.checkNotNullParameter(separator, "separator");
Intrinsics.checkNotNullParameter(prefix, "prefix");
Intrinsics.checkNotNullParameter(postfix, "postfix");
StringBuilder result = new StringBuilder(prefix);
int index = 0;
for (Iterator var7 = ((Iterable) collection).iterator(); var7.hasNext(); ++index) {
Object element = var7.next();
if (index > 0) {
result.append(separator);
}
result.append(element);
}
result.append(postfix);
String var10000 = result.toString();
Intrinsics.checkNotNullExpressionValue(var10000, "result.toString()");
return var10000;
}
// $FF: synthetic method
public static String joinToString$default(Collection var0, String var1, String var2, String var3, int var4, Object var5) {
if ((var4 & 2) != 0) {
var1 = ",";
}
if ((var4 & 4) != 0) {
var2 = "";
}
if ((var4 & 8) != 0) {
var3 = "";
}
return joinToString(var0, var1, var2, var3);
}
@JvmOverloads
@NotNull
public static final String joinToString(@NotNull Collection collection, @NotNull String separator, @NotNull String prefix) {
return joinToString$default(collection, separator, prefix, (String) null, 8, (Object) null);
}
@JvmOverloads
@NotNull
public static final String joinToString(@NotNull Collection collection, @NotNull String separator) {
return joinToString$default(collection, separator, (String) null, (String) null, 12, (Object) null);
}
@JvmOverloads
@NotNull
public static final String joinToString(@NotNull Collection collection) {
return joinToString$default(collection, (String) null, (String) null, (String) null, 14, (Object) null);
}
public static final void main() {
List list = CollectionsKt.listOf(new Integer[]{1, 2, 3});
String var1 = joinToString((Collection) list, ";", "(", ")");
System.out.println(var1);
var1 = joinToString((Collection) list, ",", "", "");
System.out.println(var1);
var1 = joinToString$default((Collection) list, (String) null, (String) null, (String) null, 14, (Object) null);
System.out.println(var1);
var1 = joinToString$default((Collection) list, ";", (String) null, (String) null, 12, (Object) null);
System.out.println(var1);
Collection var10000 = (Collection) list;
var1 = "#";
String var2 = ";";
var1 = joinToString$default(var10000, (String) null, var1, var2, 2, (Object) null);
System.out.println(var1);
}
// $FF: synthetic method
public static void main(String[] var0) {
main();
}
}
// 파일 이름 join
package part3.strings
import java.lang.StringBuilder
fun <T> joinToString( // 이 함수는 제네릭 하다 즉, 이 함수는 어떤 타입의 값을 원소로 하는 컬렉션이든 처리할 수 있다.
collection: Collection<T>,
separator: String = ",",
prefix: String = "",
postfix: String = ""
): String {
val result = StringBuilder(prefix)
for ((index, element) in collection.withIndex()) {
if (index > 0) result.append(separator) // 첫 원소 앞에는 구분자를 붙이면 안 된다.
result.append(element)
}
result.append(postfix)
return result.toString()
}
이를 자바로 변환하면
package part3.strings;
import java.util.Collection;
import java.util.Iterator;
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
@Metadata(
mv = {1, 7, 1},
k = 2,
d1 = {"\\u0000\\u0012\\n\\u0000\\n\\u0002\\u0010\\u000e\\n\\u0002\\b\\u0002\\n\\u0002\\u0010\\u001e\\n\\u0002\\b\\u0004\\u001a8\\u0010\\u0000\\u001a\\u00020\\u0001\\"\\u0004\\b\\u0000\\u0010\\u00022\\f\\u0010\\u0003\\u001a\\b\\u0012\\u0004\\u0012\\u0002H\\u00020\\u00042\\b\\b\\u0002\\u0010\\u0005\\u001a\\u00020\\u00012\\b\\b\\u0002\\u0010\\u0006\\u001a\\u00020\\u00012\\b\\b\\u0002\\u0010\\u0007\\u001a\\u00020\\u0001¨\\u0006\\b"},
d2 = {"joinToString", "", "T", "collection", "", "separator", "prefix", "postfix", "playground.main"}
)
public final class JoinKt {
}
package part3;
import part3.strings.JoinKt;
import java.util.Arrays;
import java.util.List;
public class CallJoin {
public static void main(String[] args) {
List<Integer> list = Arrays.asList(1, 2, 3);
System.out.println(JoinKt.joinToString(list, ",", "", ""));
}
}
@file:JvmName("StringFunctions")
package part3.strings
import java.lang.StringBuilder
fun <T> joinToString( // 이 함수는 제네릭 하다 즉, 이 함수는 어떤 타입의 값을 원소로 하는 컬렉션이든 처리할 수 있다.
collection: Collection<T>,
separator: String = ",",
prefix: String = "",
postfix: String = ""
): String
const val UNIX_LUNE_SEPARATOR = "\\n" // 최상위 프로퍼티
public static final String UNIX_LUNE_SEPARATOR="\\n";
package part3
fun String.lastChar(): Char = this.get(this.length - 1) // this -> 수신 객체
// String -> 수신 객체 타입
수신 객체 타입
이라 부르며, 확장 함수가 호출되는 대상이 되는 값(객체)을 수신 객체
라고 부른다.println("Kotlin".lastChar())
fun String.lastChar(): Char = get(length - 1) // 수신 객체 멤버에 this 없이 접근할 수 있다.
import strings.lastChar
import strings.*
import strings.lastChar as last
val c = "Kotlin".last()
/* 자바 */
char c=StringUtilKt.lastChar("Java");
package part3.strings
fun <T> Collection<T>.joinToString( // Collection<T>에 대한 확장 함수를 선언한다.
separator: String = ",", // 파라미터의 디폴트 값을 지정한다.
prefix: String = "",
postfix: String = ""
): String {
val result = StringBuilder(prefix)
for ((index, element) in this.withIndex()) { //this 는 수신 객체를 가리킨다. 여기서는 T 타입의 원소로 이뤄진 컬렉션이다.
if (index > 0) result.append(separator)
result.append(element)
}
result.append(postfix)
return result.toString()
}
fun Collection<String>.join(
separator: String = ",",
prefix: String = "",
postfix: String = ""
) = joinToString(separator, prefix, postfix)
fun main() {
val list = listOf(1, 2, 3)
println(list.joinToString(separator = ";", prefix = "(", postfix = ")"))
println(listOf("one", "two", "eight").join(" "))
}
package part3
open class View {
open fun click() = println("View clicked")
}
class Button : View() {
override fun click() = println("Button clicked")
}
fun main() {
val view: View = Button()
view.click() // view에 저장된 값의 실제 타입에 따라 호출할 메서드가 결정된다.
}
// >> Button clicked
package part3
fun View.showOff() = println("I'm a view!")
fun Button.showOff() = println("I'm a button!")
fun main() {
val view: View = Button()
println(view.showOff())
}
// >>I'm a view!
val String.lastChar: Char
get() = get(length - 1)
var StringBuilder.last: Char
get() = get(length - 1)
set(value: Char) {
this.setCharAt(length - 1, value)
}
package part3
fun main() {
val strings: List<String> = listOf("first", "second", "fourteenth")
val numbers: Collection<Int> = setOf(1, 14, 2)
println(strings.last())
println(numbers.max())
}
val list = listOf(2, 3, 5, 7, 11)
public fun <T> listOf(vararg elements: T): List<T> = if (elements.size > 0) elements.asList() else emptyList()
fun main(args: Array<String>) {
val list = listOf("args: ", *args) // 스프레드 연산자가 배열의 내용을 펼쳐준다
println(list)
}
package part3
fun main(args: Array<String>) {
val map = mapOf(1 to "one", 2 to "two", 3 to "three")
}
1.to("one") // to 메서드를 일반적인 방식으로 호출함
1 to "one" // to 메서드를 중위 호풀 방식으로 호출함
val list = listOf(1, 2, 3)
mapOf(1 to "one", "one" to 1, list to list.size())
package part3
infix fun Any.to(other: Any) = Pair(this, other)
// 이 to 함수는 Pair의 인스턴스를 반환한다.
// Pair는 코틀린 표준 라이브러리 클래스로, 그 이름대로 두 원소로 이뤄진 순서쌍을 표현한다
// 실제로 to는 제네릭 함수
fun main() {
val (number, name) = 1 to "one"
println("$number : $name")
}
package part3
fun main() {
val collection = listOf(1, 2, 3, 4, 5)
for ((index, element) in collection.withIndex()) {
println("$index : $element")
}
}
package part3
fun main(args: Array<String>) {
println("12.345-6.A".split("\\\\.|-".toRegex()))
println("12.345-6.A".split(".", "-"))
}
package part3
fun parsePath(path: String) {
val directory = path.substringBeforeLast("/")
val fullName = path.substringAfterLast("/")
val fileName = fullName.substringBeforeLast(".")
val extension = fullName.substringAfterLast(".")
println("Dir: $directory, name: $fileName , ext: $extension")
}
fun parsePathByRegex(path: String) {
val regex = """(.+)/(.+)\\.(.+)""".toRegex()
val matchResult = regex.matchEntire(path)
if (matchResult != null) {
val (directory, fileName, extension) = matchResult.destructured
println("Dir: $directory, name: $fileName , ext: $extension")
}
}
fun main(args: Array<String>) {
parsePath("/User/yole/kotlin-book/chapter.adoc")
parsePathByRegex("/User/yole/kotlin-book/chapter.adoc")
val kotlinLogo = """| //
.| //
.|/ \\ """
println(kotlinLogo.trimMargin("."))
}
val price = """${'$'}99.9"""
package part3
class User(
val id: Int,
val name: String,
val address: String
)
fun saveUser(user: User) {
if (user.name.isEmpty()) {
throw IllegalArgumentException("Can't save user ${user.id}: empty Name")
}
if (user.address.isEmpty()) {
throw IllegalArgumentException("Can't save user ${user.address}: empty Address")
}
// user를 데이터베이스에 저장한다.
}
fun main(args: Array<String>) {
saveUser(User(1, "", ""))
}
package part3
class User(
val id: Int,
val name: String,
val address: String
)
fun saveUser(user: User) {
fun validate(
user: User,
value: String,
fieldName: String
) {
if (value.isEmpty()) {
throw IllegalArgumentException("Can't save user ${user.id}: empty $fieldName")
}
}
validate(user, user.name, "Name")
validate(user, user.address, "Address")
// user를 데이터베이스에 저장한다.
}
fun main(args: Array<String>) {
saveUser(User(1, "", ""))
}
package part3
class User(
val id: Int,
val name: String,
val address: String
)
fun saveUser(user: User) {
fun validate(
value: String, // 이제 saveUser 함수의 user 파라미터를 중복 사용하지않는다
fieldName: String
) {
if (value.isEmpty()) {
throw IllegalArgumentException("Can't save user ${user.id}: empty $fieldName") // 바깥 함수의 파라미터에 접근할 수 있다.
}
}
validate(user.name, "Name")
validate(user.address, "Address")
// user를 데이터베이스에 저장한다.
}
fun main(args: Array<String>) {
saveUser(User(1, "", ""))
}
package part3
class User(
val id: Int,
val name: String,
val address: String
)
fun User.validateBeforeSave() {
fun validate(
value: String, // 이제 saveUser 함수의 user 파라미터를 중복 사용하지않는다
fieldName: String
) {
if (value.isEmpty()) {
throw IllegalArgumentException("Can't save user ${id}: empty $fieldName") // 바깥 함수의 파라미터에 접근할 수 있다.
}
}
validate(name, "Name")
validate(address, "Address")
}
fun saveUser(user: User) {
user.validateBeforeSave()
// user를 데이터베이스에 저장한다.
}
fun main(args: Array<String>) {
saveUser(User(1, "", ""))
}
[출처] Kotlin IN ACTION