danuri
오늘의 기록
danuri
전체 방문자
오늘
어제
  • 오늘의 기록 (307)
    • java (150)
      • java (33)
      • spring (63)
      • jpa (36)
      • querydsl (7)
      • intelliJ (9)
    • kotlin (8)
    • python (24)
      • python (10)
      • data analysis (13)
      • crawling (1)
    • ddd (2)
    • chatgpt (2)
    • algorithm (33)
      • theory (9)
      • problems (23)
    • http (8)
    • git (8)
    • database (5)
    • aws (12)
    • devops (10)
      • docker (6)
      • cicd (4)
    • book (44)
      • clean code (9)
      • 도메인 주도 개발 시작하기 (10)
      • 자바 최적화 (11)
      • 마이크로서비스 패턴 (0)
      • 스프링으로 시작하는 리액티브 프로그래밍 (14)
    • tistory (1)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

인기 글

태그

  • CICD
  • Bitmask
  • SWAGGER
  • 트랜잭션
  • Database
  • 도메인 주도 설계
  • Jackson
  • gitlab
  • ChatGPT
  • nuribank
  • PostgreSQL
  • DDD
  • Thymeleaf
  • docker
  • 등가속도 운동
  • connection
  • Java
  • RDS
  • AWS
  • JPA
  • Kotlin
  • Spring
  • S3
  • mockito
  • 자바 최적화
  • 마이크로서비스패턴
  • Security
  • reactive
  • POSTGIS
  • Saving Plans

최근 댓글

최근 글

hELLO · Designed By 정상우.
danuri

오늘의 기록

kotlin

[Kotlin] 코틀린에서 코드를 제어하는 방법

2023. 5. 7. 11:42

자바 개발자를 위한 코틀린 입문(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
    'kotlin' 카테고리의 다른 글
    • [Kotlin] 추가적으로 알아두어야 할 코틀린 특성
    • [Kotlin] 코틀린에서의 FP
    • [Kotlin] 코틀린에서의 OOP
    • [Kotlin] 코틀린에서 변수와 타입, 연산자를 다루는 방법
    danuri
    danuri
    IT 관련 정보(컴퓨터 지식, 개발)를 꾸준히 기록하는 블로그입니다.

    티스토리툴바