자바 개발자를 위한 코틀린 입문(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 |