자바 개발자를 위한 코틀린 입문(Java to Kotlin Starter Guide)
자바 개발자를 위한 코틀린 입문(Java to Kotlin Starter Guide) - 인프런 | 강의
이 강의를 통해 Kotlin 언어의 특성과 배경, 문법과 동작 원리, 사용 용례, Java와 Kotlin을 함께 사용할 때에 주의할 점 등을 배울 수 있습니다., - 강의 소개 | 인프런
www.inflearn.com
강의를 들으며 내용 정리
코틀린에서 제어문을 다루는 방법
if문
<java>
private void validateScoreIsNotNegative(int score) { if (score < 0) { throw new IllegalArgumentException(String.format("%s는 0보다 작을 수 없습니다.", score)); } }
<kotlin>
fun validateScoreIsNotNegative(score: Int) { // Unit(void)는 생략 가능 if (score < 0) { throw IllegalArgumentException("${score}는 0보다 작을 수 없습니다") } }
자바와 거의 차이가 없다.
Expression과 Statement
<java>
private String getPassOrFail(int score) { if (score >= 50) { return "P"; } else return "F"; }
<kotlin>
fun getPassOrFail(score: Int): String { if (score >= 50) { return "P" } else { return "F" } }
역시 자바와 거의 비슷하다.
그러나 한 가지 다른 점이 있다.
자바에서 if-else는 Statement지만, 코틀린에서는 Expression이다.
Statement: 프로그램의 문장 -> 하나의 값으로 도출되지 않는다.
Expression: 하나의 값으로 도출되는 문장.
-> Statement 안에 Expression이 포함되어 있다.
<java>
// 30 + 40 = 70이라는 하나의 결과가 나온다 (Expression이면서 Statement) int score = 30 + 40; // 컴파일 에러 -> if문을 하나의 값으로 취급하지 않는다 (Statement) String grade = if (score >= 50) { "P"; } else { "F"; } // 3항 연산자는 하나의 값으로 취급하므로 에러가 없다 (Expression이면서 Statement) String grade = score >= 50 ? "P" : "F"
<kotlin>
// 코틀린은 if문도 Expressions이기 때문에 하나의 값으로 취급할 수 있다 fun getPassOrFail(score: Int): String { return if (score >= 50) { "P" } else { "F" } }
+) 코틀린에서는 if-else를 Expression으로 사용하기 때문에 3항 연산자가 없다.
if - else if -else 문도 문법이 동일하다.
<java>
private String getGrade(int score) { if (score >= 90) { return "A"; } else if (score >= 80) { return "B"; } else if (score >= 70) { return "C"; } else { return "D"; } }
<kotlin>
fun getGrade(score: Int): String { return if (score >= 90) { "A" } else if (score >= 80) { "B" } else if (score >= 70) { "C" } else { "D" } }
+) tip
어떠한 값이 특정 범위에 포함되어 있는지 -> if (score in 0..100)
switch와 when
<java>
private String getGradeWithSwitch(int score) { switch (score / 10) { case 9: return "A"; case 8: return "B"; case 7: return "C"; default: return "D"; } }
<kotlin>
fun getGradeWithSwitch(score: Int): String { return when (score / 10) { 9 -> "A" 8 -> "B" 7 -> "C" else -> "D" } }
코틀린에서 when은 특정 값 뿐만 아니라 Expression이 들어갈 수도 있다.
fun getGradeWithSwitchV2(score: Int): String { return when (score) { in 90..99 -> "A" in 80..89 -> "B" in 70..79 -> "C" else -> "D" } }
다른 예시를 보자.
<java>
private boolean startsWithA(Object obj) { if (obj instanceof String) { return (((String) obj).startsWith("A")); } else { return false; } }
<kotlin>
fun startsWithA(obj: Any): Boolean { return when (obj) { is String -> obj.startsWith("A") // 스마트 캐스트 else -> false } }
when Expressions을 통해 더 간결하게 코드를 짤 수 있다.
코틀린 when 문법은 여러 개의 조건을 동시에 검사할 수 있다.
<java>
private void judgeNumber(int number) { if (number == 1 || number == 0 || number == -1) { System.out.println("어디서 많이 본 숫자입니디"); } else { System.out.println("1, 0, -1이 아닙니다"); } }
<kotlin>
fun judgeNumber(number: Int) { when (number) { 1, 0, -1 -> println("어디서 많이 본 숫자입니다") else -> println("1, 0, -1이 아닙니다") } }
코틀린 when 문법은 early return 처럼 동작할 수 있다.
<java>
private void judgeNumber2(int number) { if (number == 0) { System.out.println("주어진 숫자는 0입니다"); return; } if (number % 2 == 0) { System.out.println("주어진 숫자는 짝수입니다"); return; } System.out.println("주어지는 숫자는 홀수입니다"); }
<kotlin>
fun judgeNumber2(number: Int) { when { number == 0 -> println("주어진 숫자는 0입니다") number % 2 == 0 -> println("주어진 숫자는 짝수입니다") else -> println("주어지는 숫자는 홀수입니다") } }
when (값) 안에 '값' 없이 직접 number == 0과 같은 Expression을 넣을 수 있다.
코틀린에서 반복문을 다루는 방법
for-each문
<java>
List<Long> numbers = Arrays.asList(1L, 2L, 3L); for (long number : numbers) { System.out.println(number); }
<kotlin>
val numbers = listOf(1L, 2L, 3L) for (number in numbers) { // in을 사용 println(number) }
전통적인 for문
<java>
for (int i = 1; i <= 3; i++) { System.out.println(i); }
<kotlin>
for (i in 1..3) { println(i) }
내려가는 경우는?
<java>
for (int i = 3; i <= 1; i--) { System.out.println(i); }
<kotlin>
for (i in 3 downTo 1) { println(i) }
2칸씩 올라가는 경우는?
<java>
for (int i = 1; i <= 5; i += 2) { System.out.println(i); }
<kotlin>
for (i in 1..5 step 2) { println(i) }
Progressio과 Range
for문의 동작 원리를 알아보자.
..연산자: 범위를 만들어 내는 연산자
..연산자의 내부 동작은 다음과 같다.
<Primitives.kt>
public operator fun rangeTo(other: Int): IntRange
IntRagne를 리턴한다.
<Ranges.kt>
public class IntRange(start: Int, endInclusive: Int) : IntProgression(start, endInclusive, 1), ClosedRange<Int> { override val start: Int get() = first override val endInclusive: Int get() = last ... }
IntRange는 IntProgressions을 상속받는데,
IntProgression은 시작값, 끝값, 공차(기본 1)를 통해 생성한다.
즉, ..연산자는 사실 등차수열을 만들어주고 있던 것이다.
1..3: 시작값 1, 끝값 3, 공차가 1인 등차수열
3 downTo 1: 시작값 3, 끝값 1, 공차가 -1인 등차수열
1..5 step 2: 시작값 1, 끝값 5, 공차가 2인 등차수열
downTo, step도 함수다.
코틀린에서 [변수.함수이름(argument)] 대신 [변수 함수이름 argument]로 호출하는 함수를 중위 함수라고 한다.
1..5 step 2
-> 1..5: 1부터 5까지 공차가 1인 등차수열 생성
-> step 2: 등차수열에 대한 step 함수 호출
-> 1..5 step 2: 1부터 5까지 공차가 2인 등차수열 생성
while문
<java>
int i = 1; while (i <= 3) { System.out.println(i); i++; }
<kotlin>
var i = 1 while (i <= 3) { println(i) i++ }
자바와 거의 동일하다.
코틀린에서 예외을 다루는 방법
try catch finally 구문
주어진 문자열을 정수로 변경하는 예제
<java>
private int parseIntOrThrow(@NotNull String str) { try { return Integer.parseInt(str); } catch (NumberFormatException e) { throw new IllegalArgumentException(String.format("주어진 %s는 숫자가 아닙니다", str)); } }
<kotlin>
fun parseIntOrThrow(str: String): Int { try { return str.toInt() } catch (e: NumberFormatException) { throw IllegalArgumentException("주어진 ${str}는 숫자가 아닙니다") } }
실패하면 null을 반환해보자.
<java>
private Integer parseIntOrThrowV2(String str) { try { return Integer.parseInt(str); } catch (NumberFormatException e) { return null; } }
<kotlin>
fun parseIntOrThrowV2(str: String): Int? { return try { str.toInt() } catch (e: NumberFormatException) { null } }
코틀린에서 try catch 구문 역시 if else처럼 Expression이다.
Checked Exception과 Unchecked Exception
프로젝트 내 파일의 내용물을 읽어오는 예제
<java>
public void readFile() throws IOException { File currentFile = new File("."); File file = new File(currentFile.getAbsoluteFile() + "/a.txt"); BufferedReader reader = new BufferedReader(new FileReader(file)); System.out.println(reader.readLine()); reader.close(); }
<kotlin>
fun readFile() { val currentFile = File(".") val file = File(currentFile.absolutePath + "/a.txt") val reader = BufferedReader(FileReader(file)) println(reader.readLine()) reader.close() }
자바와 다르게 코틀린은 thorws 구문이 없다.
코틀린에서는 Checked Exception과 Unchecked Exception을 구분하지 않는다. 모두 Unchecked Exception으로 간주한다.
-> 따라서 IOException같은 Checked Exception이 발생해도 throws를 해주지 않는다.
+) 주의
Unchecked Exception으로 간주하는 것 뿐이지 실제 동작은 자바에서와 동일하다.
-> 즉, IOException이 발생하면 트랜잭션 롤백이 안되는 등 내부적으로는 Checked, Unchecked 구분이 필요하다.
try with resources
<java>
public void readFile(String path) throws IOException { try (BufferedReader reader = new BufferedReader(new FileReader(path))) { System.out.println(reader.readLine()); } }
<kotlin>
fun readFile(path: String) { BufferedReader(FileReader(path)).use { reader -> println(reader.readLine()) } }
코틀린에는 try with resources 구문이 없다.
대신 use라는 inline 확장함수를 사용한다.
코틀린에서 함수를 다루는 방법
함수 선언 문법
<java>
public int max(int a, int b) { if (a > b) { return a; } else { return b; } }
<kotlin>
fun max(a: Int, b: Int): Int { return if (a > b) { a } else { b } }
코틀린에서 if-else는 Expression이기 때문에 바로 return 가능하다.
+) 접근 지시어, public은 생략 가능하다.
함수가 하나의 결과값이면 block '{}' 대신 '=' 사용 가능하다.
fun max(a: Int, b: Int): Int = return if (a > b) { a } else { b }
한 줄로도 변경 가능하다. 또한, '='을 사용하는 경우 반환 타입 생략 가능하다.
fun max(a: Int, b: Int) = if (a > b) a else b
+) block '{}'을 사용하는 경우 Unit을 반환하지 않는 이상 반환 타입을 명시적으로 작성해 주어야 한다.
default parameter
주어진 문자열을 N번 출력하는 예제
<java>
public void repeat(String str, int num, boolean useNewLine) { for (int i = 1; i <= num; i++) { if (useNewLine) { System.out.println(str); } else { System.out.print(str); } } }
<kotlin>
fun repeat(str: String, num: Int, useNewLine: Boolean) { for (i in 1..num) { if (useNewLine) { println(str) } else { print(str) } } }
만약 많은 코드에서 num = 3, useNewLine = true를 사용한다면? 일일이 repeat(str, 3, true)를 입력해주기 불편하다.
<java>
public void repeat(String str, int num, boolean useNewLine) { for (int i = 1; i <= num; i++) { if (useNewLine) { System.out.println(str); } else { System.out.print(str); } } } public void repeat(String str, int num) { repeat(str, num, true); } public void repeat(String str) { repeat(str, 3, true); }
자바는 오버로딩을 사용할 수 있다.
<kotlin>
fun repeat(str: String, num: Int = 3, useNewLine: Boolean = true) { for (i in 1..num) { if (useNewLine) { println(str) } else { print(str) } } }
코틀린은 메서드를 3개나 만들 필요 없이, 파라미터 마다 default parameter를 넣어줄 수 있다.
함수 호출 시 해당 파라미터를 넣어주지 않으면 기본값을 사용한다.
+) 물론 자바와 동일하게 오버로딩을 사용할 수도 있다.
named argument (parameter)
만약, num은 그대로 3을 쓰고, useNewLine은 false를 쓰고 싶다면? repeat(str, 3, false)를 호출해야 할까? -> NO
repeat("Hello World", useNewLine = false)
useNewLine이라는 매개변수 이름을 통해 직접 값을 지정할 수 있다. 지정되지 않은 매개변수는 기본값을 사용한다.
+) 코틀린에서 자바 함수를 가져다 사용할 때는 named argument를 사용할 수 없다.
같은 타입의 여러 파라미터 받기 (가변인자)
문자열을 N개 받아 출력하는 예제
<java>
// 배열을 직접 넣거나, comma를 이용해 여러 파라미터를 넣는다 public static void main(String[] args) { String[] array = new String[]{"A", "B", "C"}; printAll(array); printAll("A", "B", "C"); } public static void printAll(String... strings) { for (String str : strings) { System.out.println(str); } }
<kotlin>
// 배열을 바로 넣는대신 스프레드 연산자(*)를 붙여주어야 한다 fun main() { val array = arrayOf("A", "B", "C") printAll(*array) printAll("A", "B", "C") } // vararg를 사용한다 fun printAll(vararg strings: String) { for (str in strings) { println(str) } }
'kotlin' 카테고리의 다른 글
[Kotlin] JPA 플러그인 정리 (0) | 2024.07.19 |
---|---|
[Kotlin] 추가적으로 알아두어야 할 코틀린 특성 (0) | 2023.06.20 |
[Kotlin] 코틀린에서의 FP (0) | 2023.06.04 |
[Kotlin] 코틀린에서의 OOP (0) | 2023.05.07 |
[Kotlin] 코틀린에서 변수와 타입, 연산자를 다루는 방법 (0) | 2023.05.07 |