BE/Kotlin

[Kotlin] Lambda Expression

멍목 2023. 3. 10. 22:28
반응형

자바 개발자를 위한 코틀린 입문

 

이 포스팅에서 작성하는 내용은 자바 개발자를 위한 코틀린 입문 에서 발췌하였습니다.

https://inf.run/BpYf

 

자바 개발자를 위한 코틀린 입문(Java to Kotlin Starter Guide) - 인프런 | 강의

이 강의를 통해 Kotlin 언어의 특성과 배경, 문법과 동작 원리, 사용 용례, Java와 Kotlin을 함께 사용할 때에 주의할 점 등을 배울 수 있습니다., - 강의 소개 | 인프런

www.inflearn.com


1. Lambda Expression

  • 코틀린에서는 기본적으로 함수가 그 자체로 값이 될 수 있다.
    즉, 변수에 할당할 수 있고, 파라미터로 넘길 수 있다. (자바에서의 함수 : 2급 시민, 코틀린에서의 함수 : 1급 시민)
  • 마지막 파라미터가 함수일 때, 소괄호 밖에 중괄호로 사용 가능하다.
  • 람다로 작성 시, 파라미터가 한 개라면 it 키워드로 직접 참조가 가능하다.
  • 람다로 여러 줄을 작성가능하며, 이 때 마지막 줄의 결과가 리턴의 반환 값이다. (return 키워드가 없더라도 알아서 반환)
  • Closure : 코틀린은 람다를 실행할 때, 람다 안에서 사용되는 변수들의 모든 값을 알고 있는다.
class Game(
    val name: String,
    val price: Int
)

fun main() {
    val gameShop =
        listOf(
            Game("lol", 1_000),
            Game("lol", 1_000),
            Game("lol", 2_000),
            Game("lol", 3_000),
            Game("maple", 1_000),
            Game("maple", 3_000),
            Game("diablo", 10_000)
        )

    // 익명함수를 사용한 방법
    // 함수의 파라미터 및 리턴타입 설정은 생략 가능하다. (Game) -> Boolean
    var isLol: (Game) -> Boolean = fun(game: Game): Boolean {
        return game.name == "lol"
    }

    // 람다 표현식을 이용한 방법
    // 함수의 파라미터 및 리턴타입 설정은 생략 가능하다. (Game) -> Boolean
    var isLol2: (Game) -> Boolean = { game -> game.name == "lol" }

    // 호출방법 1
    isLol(gameShop[0])

    // 호출방법 2
    isLol.invoke(gameShop[0])

    // Filter를 이용한 방법 1
    filterGames(gameShop, isLol)

    // Filter를 이용한 방법 2
    filterGames(gameShop) {game: Game -> game.name == "lol"}

    // Filter를 이용한 방법 3
    // 람다로 작성 시, 파라미터가 한 개라면 it 키워드로 직접 참조가 가능하다.
    filterGames(gameShop) {it.name == "lol"}
}

private fun filterGames(
    gameShop: List<Game>,
    filter: (Game) -> Boolean   // 함수의 파라미터 및 리턴타입 설정
): List<Game> {
    val games = mutableListOf<Game>()       // 가변 리스트 정의
    for(game in games){
        if(filter(game)){
            games.add(game)
        }
    }
    return games
}

// filter 를 이용
private fun filterGames2(
    gameShop: List<Game>,
    filter: (Game) -> Boolean   // 함수의 파라미터 및 리턴타입 설정
): List<Game> {
    return gameShop.filter(filter).toList()
}

 

 

2. 그 외의 함수형 프로그래밍(Java의 stream())

data class User(
    val id: Long,
    val name: String,
    val age: Long,
    val money: Long
) {
    fun nullOrValue() {
        this == null
    }
}

fun main() {
    val users =
        listOf(
            User(1,"홍길동", 4, 1_000, ),
            User(2,"홍길동", 6, 2_000, ),
            User(3,"홍길동", 5, 3_000, ),
            User(4,"홍길동", 7, 4_000, ),
            User(5,"강백호", 10, 5_000, ),
            User(6,"강백호", 11, 10_000, ),
            User(7,"강호동", 22, 50_000, )
        )

    // java stream 처럼 filter 를 이용해서 원하는 필터를 걸 수 있음
    val gildongs = users.filter {it.name == "홍길동"}
    println(gildongs)

    // 필터 내의 로직에서 index 를 확인할 때 아래와 같이 사용 가능하다.
    val gildongsWithIdx = users.filterIndexed { idx, user ->
        println(idx)
        user.name == "홍길동"
    }
    println(gildongsWithIdx)

    // .map을 이용해서 특정한 형태로 추출할 수 있다. (여기서도 마찬가지로 index 가 필요하다면, mapIndexed를 사용하면 된다.)
    var gildongsMoney = users.filter {it.name == "홍길동"}.map{user -> user.money}
    println(gildongsMoney)

    // map의 결과가 null이 아닌 것을 조회
    var gildongsMoneyNotNull = users.filter {it.name == "홍길동"}.mapNotNull{user -> user.nullOrValue()}

    // all : 람다의 결과가 모두 참이라면 true 반환, 하나라도 거짓이라면 false 반환
    var allLambda = users.all{it.name == "홍길동"}
    println("allLambda : $allLambda")

    // none : 람다의 결과가 모두 거짓이라면 true 반환, 하나라도 참이라면 false 반환
    var noneLambda = users.none{it.name == "김멍목"}
    println("noneLambda : $noneLambda")

    // any : 람다의 결과가 하나라도 참이라면 true 반환, 모두 거짓이라면 false 반환
    var anyLambda = users.any{it.name == "홍길동"}
    println("anyLambda : $anyLambda")

    // count : 말그대로 갯수를 세는 기능
    var gildongsCount = users.count{it.name == "홍길동"}
    println("gildongsCount : $gildongsCount")

    // sortedBy : 오름차순 정렬, sortedByDescending : 내림차순 정렬
    var moneySort = users.sortedBy { it.money }
    println(moneySort)
    var moneySortReverse = users.sortedByDescending { it.money }
    println(moneySortReverse)

    // distinctBy : 람다의 결과를 기준으로 중복 제거
    var userNames = users.distinctBy {user -> user.name}.map { user -> user.name }
    println("userNames : $userNames")

    // first : 첫번 째 값을 조회 (null 이면 NPE), firstOrNull : 첫번 째 값 조회(null 가능)
    // last : 마자막 값을 조회 (null 이면 NPE), lastOrNull : 마지막 값 조회(null 가능)
    var userFirst = users.first{user -> user.name == "강백호"}
    println("userFirst : $userFirst")

    // groupBy : 사람 이름을 Key로 하는 Map을 반환(value : List<User>)
    val nameMapList: Map<String, List<User>> = users.groupBy { it.name }
    println(nameMapList)

    val customMapList: Map<String, List<Long>> = users.groupBy({user->user.name}, {user->user.money})
    println(customMapList)

    // associateBy : 사람 id을 Key로 하는 Map을 반환.(value : User. 단일 객체로 반환)
    val nameMap: Map<Long, User> = users.associateBy { user -> user.id }
    println(nameMap)

    val customMap: Map<Long, Long> = users.associateBy({ user -> user.id}, { user -> user.money })
    println(customMap)

    val map: Map<String, List<User>> = users.groupBy { user->user.name }
        .filter{(K,V) -> K == "홍길동"}
    println(map)

    // flatMap : java와 기능 동일, flatten : 중첩 클래스 해제
}

 

반응형