📖
Kyu9's Repo
  • Library of mameil
  • 이슈 경험
    • 20230220_트랜잭션
    • 20230306_캐싱이슈
    • 20230722_테스트코드에서 @Transactional
    • 20230807_deadlock
  • 인턴 스터디
    • Gradle
    • Stream, Optional, 람다식
    • JVM의 메모리 구조, Garbage Collector
    • RESTful API
    • Microservice Architecture
    • HTTP
    • 웹서버란 무엇인가
    • Git Branch
    • TDD
    • Redis을 이용한 캐시
    • Thymeleaf
    • 정리가 필요한 자료들
    • SpringBoot Management
    • 테스크 코드 분할
  • 동아리 스터디
    • 기본 SQL 공부
      • SQL의 기본 개념
      • SELECT 문장을 이용하여 원하는 데이터 출력하기
        • 집합 연산자 사용하기
        • where절에 비교 연산자를 사용해보기
        • SELECT_EX
        • 산술 연산자 사용해보기
      • 단일 행 함수 사용
        • lower/upper 함수 사용하기
        • length함수 사용하기
        • concat함수 사용
        • substr/mid/substring 함수 사용
        • instr함수 사용하기
        • lpad/rpad 함수 사용하기
        • trim/ltrim/rtrim 함수 사용하기
        • replace 함수 사용하기
        • round 함수 사용하기
        • truncate 함수 사용하기
        • mod함수 사용하기
        • ceil함수 사용하기
        • floor함수 사용하기
        • power 함수 사용하기
        • Date fn(날짜 함수)
        • 형 변환 함수
        • 일반함수란
    • a-ha 실습
    • 혼자서 만들어본 게시판
    • AWS 강의
  • 학교 나머지 공부 자료
    • 웹프레임워크(Spring)
      • Spring이란?
      • Webframework1-1
      • Webframework1-2
      • SpringBoot의 특징
      • SpringBoot 생성 방법
      • Spring Data JPA
      • SpringBoot Security
      • SpringBoot HATEOAS
  • 공부 자료들
  • WS 온라인 자바 스터디
    • Week1(JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가.)
    • Week2(자바 데이터 타입, 변수 그리고 배열)
    • Week3(연산자)
    • Week4(제어문)
    • Week5(클래스)
    • Week6(상속)
    • Week7(패키지)
    • Week8(인터페이스)
    • Week9(예외처리)
    • Week10(멀티쓰레드 프로그래밍)
    • Week11(Enum)
    • Week12(Annotation)
    • Week13(I/O)
    • Week14(Generic)
    • Week15(람다식)
  • 백준문제
    • 입출력과 사칙연산
      • We love kriii(10718)
      • 고양이(10171)
      • 개(10172)
      • A+B(1000)
      • A-B(1001)
      • AxB(10998)
      • A/B(1008)
      • 사칙연산(10869)
      • 나머지(10430)
      • 곱셈(2588)
    • for문
      • 구구단(2739)
      • A+B - 3(10950)
      • 합(8393)
      • 빠른 A+B(15552)
      • N 찍기(2741)
      • 기찍 N(2742)
      • A+B - 7(11021)
      • A+B - 8(11022)
      • 별 찍기 - 1(2438)
      • 별 찍기 - 2(2439)
      • X보다 작은 수(10871)
    • if문
      • 두 수 비교하기(1330)
      • 시험 성적(9498)
      • 윤년(2753)
      • 사분면 고르기(14681)
      • 알람 시계(2884)
      • 오븐 시계(2525)
      • 주사위 세개(2480)
      • 영수증(25304)
    • While문
      • A+B - 5(10952)
      • A+B - 4(10951)
      • 더하기 사이클(1110)
    • 1차원 배열
      • 최소, 최대(10818)
      • 최댓값(2562)
      • 숫자의 개수(2577)
      • 나머지(3052)
      • 평균(1546)
      • OX퀴즈(8958)
      • 평균은 넘겠지(4344)
    • 함수
      • 정수N개의 합(15596)
      • 셀프 넘버(4673)
      • 한수(1065)
    • 문자열
      • 아스키코드(11654)
      • 숫자의 합(11720)
      • 알파벳 찾기(10809)
      • 문자열 반복(2675)
      • 단어 공부(1157)
      • 단어의 개수(1152)
      • 상수(2908)
      • 다이얼(5622)
      • 크로아티아 알파벳(2941)
      • 그룹 단어 체커(1316)
    • 기본수학-1
      • 손익분기점(1712)
      • 벌집(2292)
      • 분수찾기(1193)
      • 달팽이는 올라가고 싶다(2869)
      • ACM 호텔(10250)
      • 부녀회장이 될테야(2775)
      • 설탕 배달(2839)
      • 큰 수 A+B(10757)
      • Fly me to the Alpha Centauri(1011)
    • 기본수학-2
      • 소수 찾기(1978)
      • 소수(2581)
      • 소인수분해(11653)
      • 소수 구하기(1929)
      • 베르트와 공존(4948)
    • 재귀
      • 하노이 탑 이동 순서(11729)
      • 피보나치 수 5(10870)
      • 별 찍기(2447)
    • 브루트 포스
      • 블랙잭(2798)
      • 분해합(2231)
      • 덩치(7568)
      • 체스판 다시 칠하기(1018)
      • 영화감독 슘(1436)
    • 집합과 맵
      • 숫자 카드(10815)
      • 문자열 집합(14425)
      • 숫자 카드2(10816)
      • 듣보잡(1764)
      • 대칭 차집합(1269)
      • 서로 다른 부분 문자열 갯수(11478)
    • 정렬
      • 수 정렬하기(2750)
      • 수 정렬하기 2(2751)
      • 수 정렬하기 3(10989)
      • 통계학(2108)
      • 소트인사이드(1427)
      • 좌표 정렬하기(11650)
      • 좌표 정렬하기2(11651)
      • 단어 정렬(1181)
      • 나이순 정렬(10814)
      • 커트라인(25305)
      • 좌표압축(18870)
    • 백트래킹
      • N과 M - 1(15649)
      • N과 M - 2(15650)
      • N과 M - 3(15651)
      • N과 M - 4(15652)
      • N-Queen(9663)
      • 스도쿠(2580)
      • 연산자 끼워넣기(14888)
      • 스타트와 링크(14889)
    • 이분 탐색
      • 수 찾기(1920)
    • 동적계획법
      • 피보나치 함수(1003)
      • 신나는 함수 실행(9184)
      • 01타일(1904)
      • 파도반 수열(9461)
      • RGB거리(1149)
      • 정수 삼각형(1932)
      • 계단 오르기(2579)
      • 1로 만들기(1463)
      • 쉬운 계단 수(10844)
      • 포도주 시식(2156)
      • 가장 긴 증가하는 부분 수열(11053)
      • 가장 긴 바이토닉 부분 수열(11504)
      • 전깃줄(2565)
      • LCS(9251)
      • 연속합(1912)
      • 평범한 배낭(12865)
      • 더하기(9095)
    • DFS와 BFS
      • 미로탐색(2178)
      • 바이러스(2606)
      • DFS와 BFS(1260)
      • 단지번호붙이기(2667)
      • 전쟁 - 전투(1303)
      • 숨바꼭질(1697)
      • 데스 나이트(16948)
      • 나이트의 이동(7562)
      • 녹색 옷 입은 애가 젤다지?(4485)
      • 음식물 피하기(1743)
      • A->B (16953)
      • 숨바꼭질 3(13549)
      • 숨바꼭질 2(12851)
    • 구현
      • 치즈(2636)
  • 프로그래머스 문제
    • SQL
      • Animal Table - Oracle
      • Animal Table - MySQL
      • Animal Table2 - Oracle
      • Animal Table 3,4 - Oracle
    • Lv1
      • 두 개 뽑아서 더하기
      • 제일 작은 수 제거하기
      • 문자열 내 p와 y의 개수
      • 예산
      • 자릿수 더하기
      • 두 정수 사이의 합
      • 같은 숫자는 싫어
      • 가운데 글자 가져오기
      • 수박수박수박수박수박수?
      • 나누어 떨어지는 숫자 배열
      • 2016년
      • 폰캣몬
      • 서울에서 김서방 찾기
      • 문자열을 정수로 바꾸기
      • 소수 만들기
      • 문자열 다루기 기본
      • 소수 찾기(에라토스테네스의 체)
      • 숫자 문자열과 영단어
      • 이상한 문자 만들기
      • 없는 숫자 더하기
      • 문자열 내림차순으로 배치하기
      • 문자열 내 마음대로 정렬하기
      • 약수의 개수와 덧셈
      • 콜라츠 추측
      • 자연수 뒤집어 배열로 만들기
      • 신규 아이디 추천
      • 비밀지도
      • 크레인 인형뽑기 게임
      • 실패율
      • 로또의 최고 순위와 최저 순위
      • 키패드 누르기
      • 정수 내림차순으로 배치하기
    • Lv2
      • 행렬의 곱셈
      • 영어 끝말잇기
      • 영어 끝말잇기
      • N개의 최소 공배수
      • 피보나치 수
      • 124 나라의 숫자
      • 짝지어 제거하기
      • 프린터
      • 다음 큰 숫자
      • 최댓값과 최솟값
      • 최소값 만들기
      • 숫자의 표현
      • JadenCase 문자열 만들기
      • 오픈채팅방
      • 영어 끝말잇기
      • 멀쩡한 사각형
      • 올바른 괄호
      • 위장
      • 기능개발
      • 더 맵게
      • 스킬트리
    • 완전탐색
      • 모의고사(Lv1)
      • 카펫(Lv2)
      • 소수 찾기(Lv2)
    • 정렬(Sorting)
      • K번째 수(Lv1)
      • 가장 큰 수(Lv2)
      • H-Index(Lv2)
    • 해시(Hash)
      • 완주하지 못한 선수(Lv1)
      • 전화번호 목록(Lv2)
    • 탐욕법(Greedy)
      • 체육복(Lv1)
      • 큰 수 만들기(Lv2)
      • 구명보트(Lv2)
    • 동적계획법(DP)
      • 정수 삼각형(Lv3)
    • 깊이/너비 우선 탐색(DFS/BFS)
      • 타겟 넘버(Lv2)
      • 네트워크(Lv3)
      • 단어 변환(Lv3)
  • 스프링부트 책
    • Day 1
    • Day 2
    • Day 3
    • Day 4
    • Day 5
    • Day 6
    • Day 7
    • Day 8
    • Day 9
    • Day 10
    • Day 11
    • Day 12
    • Day 13
    • Day 14
    • Day 15
    • Day 16
    • Day 17
  • JPA 책
    • 프로젝트 세팅 및 기본설정
    • 영속성 관리 개념
    • 엔티티 매핑
      • 실습 예제
    • 연관관계 매핑 기초
      • 실습 예제
    • 다양한 연관관계 매핑
      • 다대일, 일대다 관계
      • 일대일, 다대다 관계
      • 실습 예제
    • 고급 매핑
      • 상속 관계 매핑
      • @MappedSuperclass
      • 복합 키와 식별 관계 매핑
      • 조인 테이블
    • 프록시와 연관관계 관리
      • 프록시
      • 즉시 로딩과 지연 로딩
      • 영속성 전이, 고아 객체
    • 값 타입
      • 임베디드 타입
      • 값 타입과 불변 객체
      • 값 타입의 비교, 컬렉션
    • 객체지향 쿼리 언어
      • JPQL part1
      • JPQL part2
      • JPQL part3
      • QueryDSL
      • NativeSQL
      • 객체지향 쿼리 심화
    • 응용 애플리케이션
      • 엔티티 설정
    • 스프링 데이터 JPA
      • 공통 인터페이스
  • Kotlin In Action
    • 코틀린의 특징
    • 코틀린의 기초
    • 함수 정의와 호출
    • 클래스, 객체, 인터페이스
    • 람다 방식
    • 코틀린 타입 시스템
    • 연산자 오버로딩과 기타 관례
    • 고차함수
    • 제네릭스
    • 애노테이션과 리플렉션
    • 코루틴
  • Oracle
    • Oracle 기본
    • Oracle 심화
  • SQL_연습
    • Revising the Select Query
    • Basic Select
    • Advanced Select
    • Basic Select 2
  • SQL 첫걸음(책)
    • Day 1
    • Day 2
    • Day 3
    • Day 4
    • Day 5
    • Day 6
    • Day 7
    • Day 8
    • Day 9
    • Day 10
    • Day 11
    • Day 12
    • Day 13
    • Day 14
    • Day 15
    • Day 16
    • Day 17
    • Day 18
    • Day 19
    • Day 20
    • Day 21
    • Day 22
    • Day 23
    • Day 24
    • Day 25
    • Day 26
    • Day 27
    • Day 28
    • Day 29
    • Day 30
  • 더 자바 코드를 조작하는 다양한 방법
    • JVM 이해하기
    • 바이트코드 조작
    • 리플렉션
    • 다이나믹 프록시
    • 애노테이션 프로세서
  • 더 자바, 애플리케이션을 테스트하는 다양한 방법
    • JUnit5
    • Mockito
    • 도커와 테스트
    • 성능, 운영이슈, 아키텍처 테스트
  • 이펙티브 자바
    • item1 - 생성자 대신 정적 팩토리 메소드를 고려하라
    • item2 - 생성자에 매개변수가 많다면 빌더를 고려하라
    • item3 - 생성자나 열거타입으로 싱글턴임을 보증하라
    • item4 - 인스턴스화를 막기 위해선 private 생성자를 사용하라
    • item5 - 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라
    • item6 - 불필요한 객체 생성을 피하라
    • item7 - 다 쓴 객체 참조를 해제하라
    • item8 - finalizer와 cleaner 사용을 피하라
    • item9 - try-finally 보다 try-with-resources을 사용하라
    • item10 - equals는 일반 규약을 지켜 재정의하라
    • item11 - equals을 재정의하려면 hashCode도 재정의하라
    • item12 - toString을 항상 재정의하라
    • item13 - clone 재정의는 주의해서 진행하라
    • item14 - Comparable을 구현할지 고민하라
  • Elastic Search
    • 강의 Summary
    • Elastic Summary 개념 정리
    • Elastic Summary 적용 정리
  • 토비의 스프링 강의
    • 스프링부트 살펴보기
    • 독립 실행형 서블릿 애플리케이션
  • k8s
    • minikube 설치
    • jenkins 추가
  • Article
    • Choosing the Right MessageBroker
Powered by GitBook
On this page
  • 고차 함수 정의
  • 인라인 함수
  • 고차 함수 안에서 흐름 제어

Was this helpful?

  1. Kotlin In Action

고차함수

어떻게 보면 메소드 체이닝과 같이 코드의 중복을 없애고 변수를 만들고 그 변수로 로직이 돌아가는 그런느낌이 아니니라 함수에서 변수가 생기면 그 변수를 바로바로 람다를 통해서 작업할 수 있다 고차함수란 다른 함수를 인자로 받거나 함수를 반환해주는 함수이다 -> 함수 참조를 사용해서 함수를 값으로 표현할 수 있다 그래서 고차함수는 람다나 함수 참조를 인자로 넘길 수 있거나 람다나 함수 참조를 반환하는 함수이고 함수를 인자를 받는 동시에 함수를 반환하는 것도 가능하다

고차 함수 정의

코틀린에서는 타입 추론을 통해서 변수 타입을 지정하지 않아도 람다를 변수에 대입할 수 있다

//기본적으로 배우고 사용하던 방법 -> 자동으로 타입을 인지해서 리턴 타입을 선언하지 않아도 잘 적용되었음
val sum = {x: Int, y: Int -> x+y}
val action = { println("fun")}
    
//물론 직접 명시하는 것을 통해서 어떤 타입을 사용할지에 대한 정의도 가능
val sum2: (Int, Int) -> Int = {x, y -> x+y}
val action2: () -> Unit = { println("fun")}

이렇게 파라미터로 들어가는 타입을 괄호 안에 넣어주고, 그 뒤에 화살표를 통해서 리턴 타입을 명시해준다 익명함수처럼 리턴값이 따로 존재하지 않는 케이스에서는 자바에서의 void와 같은 의미인 Unit을 통해서 명시해줄 수 있다 없다고해서 명시를 안해주면 안된다 추가로 nullable 타입을 리턴하는 것도 가능한데 ((Int, Int)->Int)? = null 이렇게 널러블 타입을 리턴하는이 가능하다는 점이다

그래서 고차함수를 어떻게 선언하냐

    fun twoAndThree(operation: (Int, Int) -> Int){
        val result = operation(2, 3)
        println("$result is RESULT")
    }

    twoAndThree{ a, b -> a+b} //5
    twoAndThree{ a, b -> a*b} //6
    

이 함수는 2,3에 대해서 인자로 받은 연산을 수행하고 결과를 내보낸다 이렇게 인자로 받은 함수를 호출하는 구분은 일반 함수를 호출하는 것과 동일하다 심지어 자바에서도 코틀린 함수 타입을 사용할 수 있다 어짜피 컴파일된 코드 안에서 함수 타입은 일반 인터페이스로 변경되기 때문에 함수 타입의 변수는 FunctionN 인터페이스를 구현하는 객체를 저장 한다 코틀린 표준 라이브러리 함수는 인자의 갯수에 따라 Function0 (인자가 없는 함수), Function1<P1, R> (인자가 하나 있는 함수) 이렇게 여러개 인터페이스를 제공하고 이러한 인터페이스 내부에는 invoke 메소드가 있고 이걸 통해서 함수를 실행한다 그래서 함수 타입인 변수는 인자 갯수에 따라 적당한 FunctionN 인터페이스를 구현하는 클래스의 인스턴스를 저장하고 invoke 메소드에 람다의 본문이 들어가는 방식이다 위에서 코틀린에서 사용한 것 처럼 사용하되, Unit 대신 void 으로 수정이 되어야함

함수에서 함수를 반환하는 경우도 있다 이런건 이제 상태나 조건에 따라서 로직이 달라지는 경우에 사용할 수 있다 책에서 예시로 들어준 부분은 자신이 선택한 배송 수단에 따라서 배송비를 계산하는 로직이 다른 케이스를 적절한 로직을 선택해서 함수로 반환하는 함수를 만드는 것을 보여주었다

package me.kyu9.ktexercise.ch7

class Order(val itemCount: Int) {}

fun getShippingCalculator(type: String): (Order) -> Double { // 함수를 리턴하는 함수를 선언
    
    //함수에서 람다를 리턴
    if(type == "DELIVERY"){
        return { order -> 2.0 * order.itemCount }
    }else{
        return { order -> 1.5 * order.itemCount }
    }
}

fun main() {
    //리턴받은 함수를 변수에 저장하는데 어떠한 타입의 로직인지를 명시해서 해당 변수에 저장을 해둠
    val calculator = getShippingCalculator("EXPIRE")
    //리턴받은 함수를 호출해서 해당 객체가 무엇이냐에 따라서 금액 계산 
    println("calculated : ${calculator(Order(20))}")

}

이렇게 다른 함수를 리턴하는 함수를 정의하기 위해서는 함수의 리턴 타입으로 함수 타입을 지정해주어야 한다

함수타입과 람다식은 중복 제거에 스페셜리스트이다 람다를 사용하니까 복잡한 구조의 코드도 간결하게 사용될 수 있다 그리고 코틀린스럽게 만드는 것이 람다를 적극 활용한다는 의미이다 중복을 없앤다는 것은 즉 중복되는 코드를 람다로 만드는 방식으로 없앤다는 의미이다... 일단 많은 예시를 눈으로 익히고 봐보자

인라인 함수

근데 람다는 가독성도 그렇고 코드를 간단하게 잘 만들어주는 방식이다 근데 좋은건 알겠는데 실제로 성능도 그럼 좋을려나? 일단 코틀린이 람다를 익명 함수로 컴파일하지만 그렇다고 새로운 클래스를 만드는 것은 아니다 하지만 람다가 변수를 잡는다면 람다가 생성될때마다 새로운 익명 클래스가 생성되긴 한다 이런 경우에 실행될 때 그 익명 클래스를 만드는데 추가적인 비용이 들긴 한다 그래서 사실 람다를 사용하면 그냥 로직을 함수로 뺴서 그 함수를 사용하는 것 보다 효율성에서 떨어진다 그래서 반복되는 로직을 라이브러리로 빼되, 컴파일러가 자바의 일반 코드처럼 생성할 수는 없을까 -> 이걸 inline 이 해준다 inline 을 함수에 붙히면 컴파일러는 그 함수를 호출하는 모든 문장을 함수 본문에 해당하는 바이트코드로 변경해준다

함수에 inline을 선언하면 함수를 호출하는 코드를 함수를 호출하는 바이트코드 대신에 함수 본문을 번역한 바이트 코드로 컴파일해주는 것이다 그니까 간단하게 함수를 호출하는 코드에 함수를 호출하는놈이 오는게 아니라 실제 함수본문인 바이트코드화되어서 넘어온다는 것이구나 물론 람다의 본문도 넣어줄 수 있어서 해당 inline 함수 내부에서 원하는 작업을 진행하는 것도 가능하다 여기서 람다의 본문으로부터 만들어지는 바이트코드는 그 람다를 호출하는 코드 정의의 일부분으로 간주해서 코틀린 컴파일러는 그 람다를 함수 인터페이스를 구현하는 익명 클래스로 감싸지 않는다

그래서 인라인 함수의 단점은 뭐가 있을까 인라인은 람다를 사용하는 모든 함수를 기준으로 인라인할 수 없다 함수가 인라이닝될 때 그 함수에 인자로 전달된 람다 식의 본문은 결과 코드에 직접 들어가는 것이 가능하지만 결국 함수 본문이 가서 펼쳐지는 방식이기 때문에 사용하는 방식이 한정될 수 밖에 없다 함수 본문에서 파라미터로 받은 함수를 호출하면 그 호출을 쉽게 람다로 변형할 수 있지만 파라미터로 받은 람다를 다른 변수에 저장하고 그 다음에 그 변수를 사용하면 람다를 바로 인라이닝할 수 없다 근데 일반적으로 인라인 함수의 본문에서 람다 식을 바로 호출하건 람다 식을 인자로 전달받아서 바로 호출하던 그 람다를 바로 인라이닝 할 수 있다 애초에근데 이런 경우가 아니면 컴파일러가 에러로 잡아주었다 만약에 함수에서 특정 일부 람다만 인라이닝으로 끄집어서 쓰고 싶고 나머지는 필요 없는 경우에는 내부 파라미터를 선언해줄 때 해당 익명 함수 부분에서 noinline 키워드를 통해서 인라이닝을 빼고 진행할 수 있다

뭔가 이렇게 보고있으면 그냥 사용하면 할수록 좋은 거? 라고 생각하긴하는데 막 아무런 생각 없이 쓴다고해서 좋은 것만은 아니다 결국 성능적 향상을 받는건 람다를 인자로 받는 함수 성능만 좋아진다 실제로 일반적인 함수 호출의 경우에는 JVM에서 어느정도는 지원해준다 이놈이 알아서 코드를 실행하면 바이트코드>기계어 변형과정(JustInTime)에 가장 베스트인 방향으로 호출을 인라이닝을 해주기 때문에 세세하게 들여다보고 성능적 차이를 확인해야 한다 이미 인라이닝을 해준다고 했을 때 바이트 코드에서는 각 함수 구현이 한 번만 있으면 되고, 그 함수를 호출하는 부분에서 따로 함수 코드를 중복할 필요가 없다 하지만 코틀린의 인라이닝 함수는 결국 있는 함수 바이트코드를 그대로 긁어와서 사용하기 떄문에 어떻게 보면 코드 중복이 일어나는 것이다 그래도 람다를 인자로 받는 함수를 인라이닝하면 좋은 점이 많다고 한다 일단 인라이닝을 통해서 없앨 수 있는 부가 비용이 많다 -> 함수 호출 비용을 줄이고, 람다로 표현하는 클래스와 람다 인스턴스를 생성할 필요가 없다 그리고 지금 JVM이 함수 호출과 람다를 인라이닝 해줄 정도로 스마트하지는 않다고 한다 마지막으로는 몇 가지 추가적인 기능이 있다는데 이걸 나중에 본다네? 뭐지? 그래서 결론은 이거다 -> inline 쓸 때는 함수의 크기를 확인하자 결국은 이게 모오오든 코드에 함수를 녹여서 사용하는거니까 큰 함수에다가 인라인 달고 사용하면 매우 불편할듯하다 필요하면 noinline으로 뺄껀 빼고 사용하자

참고? 예시?로 있는게 자원 관리를 위해 인라인된 람다 사용이 추가로 있었다 람다로 중복을 없앨 수 있는 일반적인 패턴 중 한 가지는 어떤 작업을 하기 위해 자원을 획득 > 작업완료 후 자원 해제 이런 흐름이다 자원의 예시로는 역시 트랜잭션, 락, 파일 이런것들이 있는데 일반적은 try-finally로 처리한다 try 이전에 자원을 잡고 finally에서 자원을 해제하는 방식으로 처리한다 코틀린에서는 withLock 이라는 라이브러리를 제공해주는데 이게 Lock 인터페이스의 확장 함수인데 사용법은 해당자원.withLock{ 자원을 사용한 로직 } 이렇게 사용하는 방식이다

고차 함수 안에서 흐름 제어

내부에 return 문에 있는 루프문을 filter 와 같은 람다를 호출하는 함수로 바꾸고 인자로 전달하는 람다 안에서 return 을 사용하면 어떨까?

package me.kyu9.ktexercise.ch8

data class Person(val name: String val age: Int)

val people = listOf(Person("Charile", 22), Person("Puth", 26))

fun lookForAlice(people: List<Person>){
    //단순 for 버전 
//    for(person in people){
//        if(person.name == "Puth"){
//            println("found Charile ${person.name}")
//            return
//        }
//        println("NOT FOUND")
//    }
    
    people.forEach{
        if(it.name == "Puth"){
            println("found Charile ${it.name}")
            return
        }
        println("NOT FOUND")
    }
}

이렇게 람다 안에서 return을 사용하면 람다로부터 변환되는 것이 아니라 그 람다를 호출하는 함수가 실행을 끝내고 리턴된다 즉 자신을 둘러싸고 있는 블록이나 그 밖의 블록을 리턴시키는 리턴문을 보고 넌로컬 리턴이라고 부른다 하지만 이렇게 리턴이 밖의 블록까지 한꺼번에 리턴시키는 경우는 람다를 인자로 받는 함수가 인라인 함수인 경우뿐이다 위의 예시인 forEach 같은 경우도 인라인 함수이기 때문에 람다 본문과 함께 인라이닝되기 때문에 리턴식이 바깥쪽 블록을 리턴할 수 있는 것이였다

물론 람다에서도 로컬 리턴을 사용할 수 있다, 만약에 리턴자체를 그렇게 외부쪽에도 영향이 가지 않고 해당 블록 내에서만 리턴이 되게 하고 싶다면 사용하는 것이 로컬 리턴이다 이렇게 보면 로컬 리턴은 약간 break 문과 같은 느낌이라고 볼 수 있을 것 같다 로컬 리턴은 람다의 실행을 끝내고 람다를 호출한 함수를 이어서 진행하게 된다 로컬 리턴과 넌로컬 리턴의 구분은 label으로 구분을 짓는다 -> 리턴으로 실행을 종료하고 싶다면 람다 식 앞에 label을 붙히고, return 뒤에 붙힌다

people.forEach label@{
        if(it.name == "Puth"){
            println("found Charile ${it.name}")
            return@label
        }
        println("NOT FOUND")
    }

이렇게 람다식 뒤에 해당 람다 식에 label 을 붙히고, 리턴할 떄 @레이블이름 이렇게 특정 이름의 label을 넘겨주는 방식으로 사용한다 물론 이렇게 이름을 정해줘서 하는 방식도 있지만 default 으로는 return@ 이렇게 까지만 해줘도 ide 에서 알아서 forEach를 명시해주더라고 그른데 만약에 로직이 길어지고 여러가지의 람다가 중첩되면 많은 위치에 return 이 들어가야한다 그리고 이런건 좀 그렇게 보이니까 익명함수를 통해서 조금 쉽게 작성하는 것이 가능하다

people.forEach(fun (person){
        if(person.name == "Charile") return
        println("${person.name} is not Charile")
    })

익명함수도 일반 함수와 같은 리턴 타입 지정 규칙이 따라가기 때문에 기존에 lable로 지정해서 리턴해줄 필요 없이도 그냥 리탄이 가능하다 넌로컬 리턴 처럼 모든 것을 리턴하는 것이 아닌 익명 함수만 리턴하는 방식이다 사실 리턴에 적용되는 규칙은 단순히 가장 안쪽의 함수를 리턴한다는 규칙이다 이렇게 익명함수를 통해서 구현하면 애초에 가장 안쪽에 있는 람다식, 함수가 가장 안쪽에 있는 함수이니 해당 리턴은 익명함수만을 리턴하는 것이다 뭐 이렇게도 사용할 수 있다고 알아두쟈

Previous연산자 오버로딩과 기타 관례Next제네릭스

Last updated 2 years ago

Was this helpful?