본문 바로가기
안드로이드/Kotlin

[Kotlin] 함수형 프로그래밍(Functional Programming), 람다(lambda)

by jinwo_o 2024. 12. 6.

프로그래밍 방식

1. 명령형 프로그래밍(Imperative Programming, IP)

  • 프로그래밍의 상태와 상태를 변경하는 구문의 관점에서 연산을 설명하는 방식
  • 무엇(What)을 ‘어떻게(How)’ 할 것인지에 집중한다.
  • 1-1. 절차지향 프로그래밍(Procedural Programming, PP) : 문제를 순차적으로 처리하여 프로그램을 만드는 방식 (C, C++)
    • 절차지향 프로그래밍은 함수를 구조화할 뿐 데이터 자체를 구조화하지 못하기 때문에, 소프트웨어의 규모가 커지거나 변화가 생기면 각각의 함수에 의존하는 부분을 매번 고쳐야 하는 등 작업이 복잡해져 스파게티 코드를 유지보수하는 데 어려움을 겪는다.
  • 1-2. 객체지향 프로그래밍(Object-Oriented Programming, OOP) : 객체들 간의 상호작용을 통해 프로그램을 만드는 방식 (C++, Java, C#)
 

[Kotlin] 객체 지향 프로그래밍(Object-Oriented Programming)

프로그래밍 방식1. 명령형 프로그래밍(Imperative Programming, IP)프로그래밍의 상태와 상태를 변경하는 구문의 관점에서 연산을 설명하는 방식무엇(What)을 ‘어떻게(How)’ 할 것인지에 집중한다.1-1.

dev-baik.tistory.com

 

 

2. 선언형 프로그래밍Declarative Programming, DP)

  • 프로그램이 무엇과 같은 지를 설명하는 방식
  • 무엇(What)을’ 할 것인지에 집중한다.
  • 2-1. 함수형 프로그래밍(Functional Programming, FP) : 수학적 함수의 계산을 통해 자료를 처리하고 함수를 조합하여 프로그램을 만드는 방식 (Kotlin)

함수형 프로그래밍

  • 모든 것을 순수 함수로 나누어 문제를 해결하는 기법
  • 함수 단위의 코드 재사용이 매우 용이하고, 불변성을 지향하기 때문에 프로그램의 동작을 예측하기가 쉬워진다.
  • 다중 스레드를 사용해도 안전하다.
    • 다중 스레드 프로그램에서는 적절한 동기화 없이 같은 데이터를 여러 스레드가 변경하는 경우 가장 많은 문제가 생긴다.
    • 불변 데이터 구조를 사용하고 순수 함수를 그 데이터 구조에 적용한다면 다중 스레드 환경에서 같은 데이터를 여러 스레드가 변경할 수 없다.
    • 따라서 복잡한 동기화를 적용하지 않아도 된다.

 

순수 함수(Pure function)

  • 함수 : 동일한 입력에 대해 항상 동일한 출력을 반환하는 것
  • 함수 내부에서 인자의 값을 변경하거나 프로그램 상태를 변경하는 *부수 효과가 없는 함수
    • 부수 효과(Side Effect)가 없는 : 다른 객체의 상태를 변경하지 않고, 함수 외부나 다른 바깥 환경과 상호작용하지 않는 것
    • 부수 효과가 있는 : 값을 반환하는 메서드나 함수가 외부 상태를 변경하는 것
  • C 언어와 달리 Kotlin 에서는 포인터 주소를 사용하지 않기 때문에, 주소 참조(Call By Reference)가 아닌 값을 복사하여 전달하는 값에 의한 호출(Call By Value)이 일반적으로 발생한다.
  • 테스트하기 쉽다 : 부수 효과가 있는 함수는 그 함수를 실행할 때 필요한 전체 환경을 구성하는 준비 코드가 따로 필요하지만, 순수 함수는 그런 준비 코드 없이 독립적으로 테스트할 수 있다.

 

불변성 (Immutability)

  • 값이나 상태를 변경할 수 없는 것
  • 함수형 프로그래밍에서는 일단 만들어지고 나면 내부 상태가 절대로 바뀌지 않는 불변 객체를 사용해 프로그램을 작성한다.
  • 불변 객체는 생성 시점 이후 한 번 정의된 상태를 유지하며 변경되지 않기 때문에, 스레드 간 안전성이 보장되어 동기화 문제를 해결할 수 있다.
  • 데이터의 상태를 변경하는 대신, 변경된 새로운 데이터를 생성하여 상태 변경으로 인한 버그 발생 가능성을 줄일 수 있습니다.

 

[ 가변성(Mutability) ]

  • 상태를 가지는 경우
  • 메모리의 저장된 값을 변경하는 행위
  • 메모리에 저장된 하나의 값을 누구나 변경할 수 있다는 것은 무분별한 상태 변경으로 이어질 수 있다.

 

[ 가변성을 제한하는 방법 ]

  • 읽기 전용 프로퍼티 val
 

[Kotlin] 변수 선언(val, var, const val)

val (value 의 약자)변경 불가능한 참조를 저장하는 변수일단 초기화하고 나면 재대입이 불가능하다. 자바로 말하자면 final 변수에 해당한다. val 변수는 블록을 실행할 때 정확히 한 번만 초기화돼

dev-baik.tistory.com

  • 읽기 전용 컬렉션
 

[Java] 읽기 전용 컬렉션(List, Set, Map), ArrayList, LinkedList, Array

List 인터페이스순서가 있는 데이터의 집합저장 순서가 유지되는 컬렉션을 구현하는 데 사용한다.같은 요소의 중복 저장을 허용한다.배열과 마찬가지로 index 로 요소를 접근하다.리스트는 데이

dev-baik.tistory.com

  • data class 의 copy() 함수
 

[Kotlin] 데이터 클래스(Data Class)

Java 에서 클래스는 Object Class 를 상속받고, Object Class 에 정의된 toString(), hashCode(), equals(other: Object) 메서드를 재정의 할 수 있다. Kotlin 에서도 Java 와 마찬가지로 Any Class 를 상속받으며 Any Class 에

dev-baik.tistory.com

 

일급 객체(First-class citizens)

  • 함수형 언어에서는 모든 것이 객체가 된다.
    • 자바에서는 클래스만이 객체가 되고 함수는 클래스 안의 메서드로 구현되지만, 함수형 언어인 코틀린에서는 함수 또한 객체로 관리할 수 있다.
  • 일급 객체 조건
    • 함수(프로그램의 행동을 나타내는 코드 조각)를 일반 값처럼 다룰 수 있다. 함수를 변수에 저장할 수 있다.
    • 함수를 인자로 다른 함수에 전달할 수 있다.
    • 다른 함수의 결과 값으로 반환될 수 있다.
  • 간결성 : 함수형 코드는 그에 상응하는 명령형 코드에 비해 더 간결하며 우아하다. (순수) 함수를 값처럼 활용할 수 있으면 더 강력한 추상화를 할 수 있고 강력한 추상화를 사용해 코드 중복을 막을 수 있다.

 

고차 함수(Higher-order function)

  • 다른 함수를 인자로 받거나, 함수를 반환하는 함수
  • 람다나 함수 참조를 인자로 넘길 수 있거나, 람다나 함수 참조를 반환하는 함수

익명 클래스(Anonymous Class)

  • 단 한번만 객체로 생성하고 더 이상 재사용되지 않는 클래스
  • 클래스 선언과 동시에 객체를 생성하는 일회용 클래스
  • 만일 어느 메서드에서 부모 클래스의 자원을 상속받아 재정의하여 사용할 자식 클래스가 한 번만 사용되고 버려질 자료형이면, 굳이 상단에 클래스를 정의하기보다는, 지역 변수처럼 익명 클래스로 정의하고 스택이 끝나면 삭제되도록 하는 것이 유지보수면에서나 프로그램 메모리면에서나 이점을 얻을 수 있다.
  • UI 이벤트 처리, 스레드 객체 등 단발성 이벤트 처리에 자주 애용된다.
  • 전혀 새로운 클래스를 익명으로 사용하는 것이 아니라, 이미 정의되어 있는 클래스의 멤버들을 재정의 하여 사용할 필요가 있을 때 그리고 그것이 일회성으로 이용될 때 사용하는 기법이다.
  • 익명 클래스 방식으로 선언한다면 오버라이딩 한 메소드 사용만 가능하고, 새로 정의된 메서드는 외부에서 사용이 불가능하다.
  • 익명 클래스도 내부 클래스의 일종이기 때문에, 외부의 지역 변수를 이용하려고 할 때 똑같이 내부 클래스의 제약을 받게 된다. 따라서 내부 클래스에서 가져올 수 있는 외부 변수는 final 상수인 것만 가져와 사용할 수 있다.
  • 익명 클래스 선언 방법
    • 부모를 상속받은 자식 익명 클래스 선언
    • 인터페이스를 구현한 익명 클래스 선언(익명 구현 객체)
      • 인터페이스의 가장 큰 본질은 다중 상속(구현)이 가능하다는 것인데, 둘 이상의 인터페이스를 갖거나, 하나의 클래스를 상속받고 동시에 인터페이스를 구현하는 형태로는 익명 구현 객체로 불가능하다.
      • 일회용 용도일지라도 다중 구현한 클래스는 따로 정의하여 사용해야 한다.
  • 그러나 익명 내부 클래스를 사용하여 코드를 함수에 넘기거나 변수에 저장할 수 있기는 하지만 상당히 번거롭다.

 

람다(람다식, 람다 표현식)

  • 다른 함수에 넘길 수 있는 작은 코드 조각
  • 익명 함수를 간단히 표현하는 함수로서, 값처럼 여러 곳에 전달할 수 있는 동작의 모음이다.
  • 인터페이스로만 만들 수 있다.
  • 자바 8 이전에는 메서드에 인자로 익명 클래스의 인스턴스를 만들어야 했다. 코틀린에서는 익명 클래스 인스턴스 대신 람다를 넘길 수 있다.
    • 이런 코드가 작동하는 이유는 익명 클래스에 추상 메소드가 단 하나만 존재하기 때문이다. (함수형 인터페이스(SAM(Single Abstract Method) 인터페이스)
  • 외부 변수를 캡처하지 않는 경우(외부 상태에 의존하지 않는 경우), 람다 인스턴스는 한 번만 생성되고 재사용할 수 있다.
    • 람다 표현식 내에서 외부 변수를 사용하지 않고, 오직 람다 자체 내에서 정의된 로컬 변수나 상수만 사용하는 경우
    • 그러나 객체를 명시적으로 선언하는 경우(익명 클래스를 생성하는 경우), 메서드를 호출할 때마다 새로운 객체가 생성된다.
  • 그러나 람다가 외부 변수를 캡처하는 경우, 람다가 생성되는 시점마다 새로운 익명 클래스 객체가 생성된다.
    • 이런 경우에는 실행 시점에 익명 클래스가 생성되면서 추가 비용이 발생하므로, 일반 함수를 사용한 구현보다 덜 효율적이다.

 

인라인 함수(Inline Function)

  • 람다가 외부 변수를 캡처하는 경우, inline 키워드를 사용한다.
  • inline 변경자를 함수에 붙이면, 컴파일러는 그 함수를 호출하는 모든 문장을 함수 본문에 해당하는 바이트코드로 바꿔치기해준다.
  • 객체가 항상 새로 생성되는 것이 아니라 해당 함수의 내용을 호출한 함수에 넣는 방식으로 컴파일 코드를 작성한다.
  • 부가 비용을 상당히 줄일 수 있다. 함수 호출 비용을 감소시킬 뿐만 아니라, 람다를 표현하는 클래스와 해당 람다 인스턴스에 필요한 객체를 생성하지 않아도 된다.
  • 인라이닝하는 함수가 큰 경우, 함수의 본문에 해당하는 바이트코드를 모든 호출 지점에 복사해 넣으면 전체 바이트코드의 크기가 상당히 커질 수 있다.

 

코틀린의 특징 Deep Dive: Functional Programming(함수형 프로그래밍)

Kotlin in Action의 1장은 코틀린에 대해 간단히 소개하는 내용이다. 따라서 1장을 따로 정리하다기 보다는 코틀린이라는 언어에 대해 궁금하거나 알고 싶은 점을 Deep Dive하는 시간을 스터디원들과

cn-c.tistory.com

 

Kotlin In Action 1장

코틀린은 자바 플랫폼에서 돌아가는 새로운 프로그래밍 언어다. 간결하고 실용적이며, 자바 코드와의 상호운용성을 중시한다. 현재 자바가 사용 중인 곳이라면 거의 대부분 코틀린을 활용할 수

velog.io

 

Java 익명 클래스

익명 클래스 클래스 중에는 단 한번만 객체로 생성하고 더 이상 재사용되지 않는 클래스가 있다. 예를 들어 이벤트 처리, 스레드 객체는 보통 프로그램에서 단 한번만 사용된다. 만약 이러한 객

gunjoon.tistory.com

 

☕ 익명 클래스(Anonymous Class) 사용법 총정리

익명 클래스 (Anonymous Class) 익명 클래스는 내부 클래스(Inner class) 일종으로 단어 그대로 이름이 없는 클래스를 말한다. 익명, 이름이 없다는 것은 별로 기억되지 않아도 된다는 것이며, 나중에 다

inpa.tistory.com

 

Kotlin In Action 5장

람다 식과 멤버 참조. 함수형 스타일로 컬렉션 다루기. 시퀀스: 지연 컬렉션 연산. 자바 함수형 인터페이스를 코틀린에서 사용. 수신 객체 지정 람다 사용. 람다 식 또는 람다 : 다른 함수에 넘길

velog.io

 

[코틀린] 인라인 함수

코틀린 - inline 키워드

velog.io

 

Kotlin In Action 8장

함수 타입. 고차 함수와 코드를 구조화할 때 고차 함수를 사용하는 방법. 인라인 함수. 비로컬 return과 레이블. 무명 함수 다른 함수를 인자로 받거나 함수를 반환하는 함수. 코틀린에서는 람다나

velog.io