Notice
Recent Posts
Recent Comments
Link
반응형
| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 | 31 |
Tags
- 티스토리챌린지
- 이차전지관련주
- 이펙티브자바
- 자바
- 예제로 배우는 스프링 입문
- Spring
- effectivejava
- Effective Java 3
- Effective Java
- 김영한
- Sort
- 카카오
- 스프링핵심원리
- ElasticSearch
- 자바스크립트
- 스프링부트
- java
- JavaScript
- 알고리즘정렬
- k8s
- 스프링
- 알고리즘
- kubernetes
- Kotlin
- 이펙티브 자바
- 스프링 핵심원리
- 오블완
- MongoDB
- 엘라스틱서치
- 클린아키텍처
Archives
- Today
- Total
Kim-Baek 개발자 이야기
Kotlin 함수 완벽 가이드 | fun으로 시작하는 간결한 코드 본문
반응형
이 글을 읽으면: Java 메서드보다 훨씬 강력하고 유연한 Kotlin 함수 작성법을 배울 수 있습니다. 단일 표현식 함수, 기본 매개변수, Named Arguments, 확장 함수까지 실전 예제로 마스터하세요.
📌 목차
- 들어가며 - Java 메서드의 불편함
- 함수 기본 문법 - fun 키워드
- 반환 타입과 Unit
- 단일 표현식 함수 - 한 줄로 끝내기
- 기본 매개변수 - 오버로딩 필요 없음
- Named Arguments - 가독성 극대화
- 가변 인자 - vararg
- 확장 함수 - 기존 클래스 확장
- 마무리 - 다음 편 예고
들어가며 - Java 메서드의 불편함
Java로 간단한 계산 메서드를 만들 때 이런 경험 있으신가요?
// Java - 너무 장황함
public class MathUtils {
// 1. 항상 클래스 안에 있어야 함
public static int add(int a, int b) {
return a + b;
}
// 2. 오버로딩으로 기본값 구현
public static int add(int a) {
return add(a, 0);
}
// 3. 메서드명으로만 구분
public static double calculateDiscount(double price, double rate) {
return price * (1 - rate);
}
// 4. 가변 인자
public static int sum(int... numbers) {
int result = 0;
for (int num : numbers) {
result += num;
}
return result;
}
}
Kotlin은 이렇게 간단합니다:
// Kotlin - 깔끔하고 직관적
fun add(a: Int, b: Int = 0) = a + b // 기본값 지원, 한 줄 함수
fun calculateDiscount(price: Double, rate: Double = 0.1) =
price * (1 - rate) // Named Arguments 가능
fun sum(vararg numbers: Int) = numbers.sum() // 가변 인자
// 확장 함수 - 기존 클래스에 메서드 추가
fun String.isValidEmail() = this.contains("@")
오늘은 이 강력한 함수 기능들을 하나씩 배워보겠습니다!
함수 기본 문법 - fun 키워드

기본 함수 선언
// 형식: fun 함수명(매개변수: 타입): 반환타입 { ... }
fun greet(name: String): String {
return "안녕하세요, ${name}님!"
}
fun main() {
val message = greet("규철")
println(message) // 안녕하세요, 규철님!
}
Java와 비교
// Java - public static 필수
public class Utils {
public static String greet(String name) {
return "안녕하세요, " + name + "님!";
}
}
// 사용
String message = Utils.greet("규철");
// Kotlin - 클래스 없이 최상위 함수 가능
fun greet(name: String): String {
return "안녕하세요, ${name}님!"
}
// 사용
val message = greet("규철")
매개변수 없는 함수
fun getCurrentTime(): String {
return java.time.LocalDateTime.now().toString()
}
fun main() {
println(getCurrentTime())
}
매개변수 여러 개
fun calculateBMI(weight: Double, height: Double): Double {
return weight / (height * height)
}
fun main() {
val bmi = calculateBMI(70.0, 1.75)
println("BMI: $bmi") // BMI: 22.857142857142858
}
반환 타입과 Unit
반환 타입 명시
fun add(a: Int, b: Int): Int {
return a + b
}
fun isPositive(number: Int): Boolean {
return number > 0
}
fun getUser(id: String): User {
return User(id, "규철")
}
Unit - 반환값이 없을 때
Java의 void와 같지만, Kotlin에서는 Unit이 실제 객체입니다.
fun printMessage(message: String): Unit {
println(message)
}
// Unit은 생략 가능
fun printMessage2(message: String) {
println(message)
}
fun main() {
printMessage("안녕하세요")
printMessage2("반갑습니다")
}
Java와 비교
// Java - void
public static void printMessage(String message) {
System.out.println(message);
}
// Kotlin - Unit (생략 가능)
fun printMessage(message: String) {
println(message)
}
Nothing - 절대 반환하지 않는 함수
fun fail(message: String): Nothing {
throw IllegalStateException(message)
}
fun main() {
val user = getUser() ?: fail("사용자를 찾을 수 없습니다")
// fail() 이후 코드는 실행되지 않음
}
단일 표현식 함수 - 한 줄로 끝내기
기본 형태
함수 본문이 한 줄이면 중괄호와 return을 생략할 수 있습니다.
// 일반 함수
fun add(a: Int, b: Int): Int {
return a + b
}
// 단일 표현식 함수
fun add(a: Int, b: Int): Int = a + b
// 반환 타입도 생략 가능 (타입 추론)
fun add(a: Int, b: Int) = a + b
실전 예제
// 최댓값 구하기
fun max(a: Int, b: Int) = if (a > b) a else b
// 절댓값
fun abs(number: Int) = if (number >= 0) number else -number
// 제곱
fun square(x: Int) = x * x
// 문자열 길이 확인
fun isLongText(text: String) = text.length > 100
fun main() {
println(max(10, 20)) // 20
println(abs(-5)) // 5
println(square(4)) // 16
println(isLongText("짧음")) // false
}
when을 사용한 단일 표현식
fun getGrade(score: Int) = when {
score >= 90 -> "A"
score >= 80 -> "B"
score >= 70 -> "C"
score >= 60 -> "D"
else -> "F"
}
fun main() {
println(getGrade(85)) // B
println(getGrade(95)) // A
}
Java와 비교
// Java - return 필수
public static int max(int a, int b) {
return (a > b) ? a : b;
}
public static String getGrade(int score) {
if (score >= 90) return "A";
else if (score >= 80) return "B";
else if (score >= 70) return "C";
else if (score >= 60) return "D";
else return "F";
}
// Kotlin - 훨씬 간결
fun max(a: Int, b: Int) = if (a > b) a else b
fun getGrade(score: Int) = when {
score >= 90 -> "A"
score >= 80 -> "B"
score >= 70 -> "C"
score >= 60 -> "D"
else -> "F"
}
기본 매개변수 - 오버로딩 필요 없음
기본값 설정
Java의 메서드 오버로딩 대신 기본값을 사용합니다.
fun greet(name: String, greeting: String = "안녕하세요") {
println("$greeting, ${name}님!")
}
fun main() {
greet("규철") // 안녕하세요, 규철님!
greet("규철", "반갑습니다") // 반갑습니다, 규철님!
}
여러 기본값
fun sendEmail(
to: String,
subject: String = "제목 없음",
body: String = "",
cc: String? = null
) {
println("받는사람: $to")
println("제목: $subject")
println("내용: $body")
cc?.let { println("참조: $it") }
}
fun main() {
sendEmail("user@example.com")
sendEmail(
to = "user@example.com",
subject = "중요한 메일",
body = "잘 부탁드립니다"
)
}
Java 오버로딩과 비교
// Java - 오버로딩으로 구현 (코드 중복)
public static void sendEmail(String to) {
sendEmail(to, "제목 없음", "");
}
public static void sendEmail(String to, String subject) {
sendEmail(to, subject, "");
}
public static void sendEmail(String to, String subject, String body) {
System.out.println("받는사람: " + to);
System.out.println("제목: " + subject);
System.out.println("내용: " + body);
}
// Kotlin - 기본값으로 간단하게
fun sendEmail(
to: String,
subject: String = "제목 없음",
body: String = ""
) {
println("받는사람: $to")
println("제목: $subject")
println("내용: $body")
}
실전 예제 - API 호출 함수
fun callApi(
url: String,
method: String = "GET",
timeout: Int = 5000,
retry: Int = 3,
headers: Map<string, string=""> = emptyMap()
) {
println("API 호출: $method $url")
println("타임아웃: ${timeout}ms")
println("재시도: ${retry}회")
}
fun main() {
// 필수 파라미터만
callApi("https://api.example.com/users")
// 일부만 커스터마이징
callApi(
url = "https://api.example.com/posts",
method = "POST",
timeout = 10000
)
}
</string,>
Named Arguments - 가독성 극대화
기본 사용법
파라미터 이름을 명시하여 순서 상관없이 호출 가능합니다.
fun createUser(
name: String,
age: Int,
email: String,
isActive: Boolean = true
) {
println("이름: $name, 나이: $age, 이메일: $email, 활성: $isActive")
}
fun main() {
// 순서대로
createUser("규철", 30, "user@example.com")
// Named Arguments로 순서 바꾸기
createUser(
email = "user@example.com",
name = "규철",
age = 30
)
// 일부만 Named Arguments
createUser("규철", 30, email = "user@example.com")
}
가독성 향상 예제
// ❌ 나쁜 예 - 무슨 의미인지 모름
createRectangle(100, 200, 50, 50)
// ✅ 좋은 예 - 명확함
createRectangle(
width = 100,
height = 200,
x = 50,
y = 50
)
Boolean 파라미터는 항상 Named Arguments!
fun saveFile(
path: String,
overwrite: Boolean,
createBackup: Boolean
) {
println("파일 저장: $path")
}
fun main() {
// ❌ 나쁜 예 - 무슨 의미인지 헷갈림
saveFile("/data/file.txt", true, false)
// ✅ 좋은 예 - 명확함
saveFile(
path = "/data/file.txt",
overwrite = true,
createBackup = false
)
}
Java에는 없는 기능!
// Java - Named Arguments 없음
createUser("규철", 30, "user@example.com", true);
// 파라미터 순서를 외워야 함!
// Kotlin - 순서 상관없이 명확하게
createUser(
age = 30,
name = "규철",
email = "user@example.com"
)
가변 인자 - vararg
기본 사용법
fun sum(vararg numbers: Int): Int {
var result = 0
for (num in numbers) {
result += num
}
return result
}
fun main() {
println(sum(1, 2, 3)) // 6
println(sum(1, 2, 3, 4, 5)) // 15
println(sum()) // 0
}
배열을 가변 인자로 전달 - Spread 연산자
fun printAll(vararg messages: String) {
messages.forEach { println(it) }
}
fun main() {
val arr = arrayOf("사과", "바나나", "오렌지")
// ❌ 에러 - 배열을 그대로 전달 불가
// printAll(arr)
// ✅ Spread 연산자 (*) 사용
printAll(*arr)
// 일반 인자와 혼합 가능
printAll("딸기", *arr, "포도")
}
실전 예제 - 로그 함수
fun log(level: String, vararg messages: Any) {
val timestamp = java.time.LocalDateTime.now()
println("[$timestamp] [$level] ${messages.joinToString(" ")}")
}
fun main() {
log("INFO", "서버 시작됨")
log("ERROR", "DB 연결 실패:", "timeout after", 5000, "ms")
log("DEBUG", "사용자", 100, "개 조회됨")
}
Java와 비교
// Java - ... 문법
public static int sum(int... numbers) {
int result = 0;
for (int num : numbers) {
result += num;
}
return result;
}
// 배열 전달
int[] arr = {1, 2, 3};
sum(arr); // OK
// Kotlin - vararg 키워드
fun sum(vararg numbers: Int) = numbers.sum()
// 배열 전달 시 * 필요
val arr = intArrayOf(1, 2, 3)
sum(*arr)
확장 함수 - 기존 클래스 확장
개념 이해
기존 클래스를 수정하지 않고 새 메서드를 추가하는 마법!
// String 클래스에 메서드 추가
fun String.isValidEmail(): Boolean {
return this.contains("@") && this.contains(".")
}
fun main() {
val email = "user@example.com"
println(email.isValidEmail()) // true
val invalid = "notanemail"
println(invalid.isValidEmail()) // false
}
실전 예제 1 - String 확장
// 전화번호 포맷팅
fun String.formatPhoneNumber(): String {
return if (this.length == 11) {
"${this.substring(0, 3)}-${this.substring(3, 7)}-${this.substring(7)}"
} else {
this
}
}
// 앞뒤 공백 제거 후 대문자 변환
fun String.trimAndUpperCase() = this.trim().uppercase()
fun main() {
val phone = "01012345678"
println(phone.formatPhoneNumber()) // 010-1234-5678
val text = " kotlin "
println(text.trimAndUpperCase()) // KOTLIN
}
실전 예제 2 - Int 확장
// 홀수/짝수 판별
fun Int.isEven() = this % 2 == 0
fun Int.isOdd() = this % 2 != 0
// 범위 안에 있는지 확인
fun Int.isBetween(min: Int, max: Int) = this in min..max
fun main() {
println(4.isEven()) // true
println(5.isOdd()) // true
println(50.isBetween(1, 100)) // true
}
실전 예제 3 - List 확장
// 두 번째 요소 가져오기
fun <T> List<T>.secondOrNull() = if (this.size >= 2) this[1] else null
// 마지막 N개 요소 가져오기
fun <T> List<T>.takeLast(n: Int) = this.drop(maxOf(0, this.size - n))
fun main() {
val numbers = listOf(1, 2, 3, 4, 5)
println(numbers.secondOrNull()) // 2
println(numbers.takeLast(2)) // [4, 5]
}
Java에서는 불가능!
// Java - Utility 클래스로만 가능
public class StringUtils {
public static boolean isValidEmail(String email) {
return email.contains("@") && email.contains(".");
}
}
// 사용
StringUtils.isValidEmail("user@example.com");
// Kotlin - 마치 원래 있던 메서드처럼
fun String.isValidEmail() = this.contains("@") && this.contains(".")
// 사용
"user@example.com".isValidEmail()
주의사항
// 확장 함수는 멤버 함수를 오버라이드할 수 없음
class MyClass {
fun method() = "멤버"
}
fun MyClass.method() = "확장" // 무시됨!
fun main() {
println(MyClass().method()) // "멤버" 출력
}
마무리 - 다음 편 예고
오늘 배운 것 ✅
- fun 키워드로 함수 선언
- 단일 표현식 함수 (=로 간결하게)
- 기본 매개변수로 오버로딩 제거
- Named Arguments로 가독성 향상
- vararg로 가변 인자 처리
- 확장 함수로 기존 클래스 확장
다음 편에서 배울 것 📚
4편: 제어 구조 완벽 가이드 | if, when, for, while 마스터하기
- if를 표현식으로 사용하기
- when - Java switch의 강력한 대안
- for 반복문과 range
- while, do-while
- break, continue, 라벨
실습 과제 💪
// 1. 단일 표현식 함수로 작성하기
// - 두 수 중 작은 값 반환
// - 문자열이 숫자인지 확인
// 2. 기본 매개변수 활용
// - 사용자 정보 출력 함수 (이름 필수, 나이/이메일 선택)
// 3. 확장 함수 만들기
// - String: 한글인지 확인
// - Int: 소수인지 확인
// - List<Int>: 평균 계산
자주 묻는 질문 (FAQ)
Q: 함수를 클래스 밖에 선언해도 되나요?
A: 네! Kotlin은 최상위 함수를 지원합니다. 유틸리티 함수는 클래스 없이 선언하세요.
Q: 기본 매개변수와 오버로딩 중 뭐가 좋나요?
A: 대부분은 기본 매개변수가 더 간결합니다. 완전히 다른 로직이면 오버로딩을 쓰세요.
Q: 확장 함수를 언제 쓰나요?
A: 기존 클래스에 자주 쓰는 유틸리티 기능을 추가할 때 씁니다.
Q: Named Arguments를 항상 써야 하나요?
A: 필수는 아니지만, Boolean 파라미터나 3개 이상 파라미터가 있으면 권장합니다.
관련 글
- Kotlin 변수와 타입 완벽 가이드 (이전 편)
- Kotlin 제어 구조 완벽 가이드 (다음 편)
- Kotlin 확장 함수 실전 활용법
💬 댓글로 알려주세요!
- 어떤 확장 함수를 만들어보고 싶으신가요?
- 기본 매개변수가 유용했던 경험이 있나요?
- 이 글이 도움이 되셨나요?
반응형
'개발 > java basic' 카테고리의 다른 글
| Kotlin 클래스와 객체 완벽 가이드 | OOP의 Kotlin 스타일 (0) | 2025.12.22 |
|---|---|
| Kotlin 제어 구조 완벽 가이드 | if, when, for, while 마스터하기 (0) | 2025.12.21 |
| Kotlin 시작하기 | 왜 Kotlin인가? 개발환경 설정부터 Hello World까지 (0) | 2025.12.21 |
| Kotlin 시작하기 | Java 개발자를 위한 첫 번째 Kotlin 코드 (0) | 2025.12.10 |
| Kotlin 테스트 완벽 가이드 | Mockito-Kotlin, JUnit5, Spring Boot Test (0) | 2025.12.09 |
Comments
