명령어 스타일 (imperative style) 컴퓨터에게 정해진 명령 또는 지시를 하나하나 내림으로써 각 명령 단계마다 시스템의 상태를 바꾼다. 처음에는 단순화하려는 의도나, 시스템이 커질수록 복잡해지며, 그 결과 코드를 더이상 유지보수할 수 없게 되고, 테스트 하기 어려워지며 코드를 추론하는데에 어려워진다. 함수형 프로그래밍 (FP, Functional Programming) 위 명령어 스타일의 대안으로, '부수 효과'를 완전히 없애는 개념이다. 함수형 프로그래밍의 전제는, 순수 함수를 통해 프로그램을 구성한다는 것이다. 부수 효과 (Side Effect) 결과를 반환하는 것 외에 무언가 다른 일을 하는 함수는 부수 효과가 있는 함수다. 변경이 일어나는 블록 외부 영역에 있는 변수를 변경한다. 데이터..
https://github.com/seohaem/kotlin-step1 변수선언 1) var 변수 선언 값 변경이 가능하다. var number1 = 10L 2) val 변수 선언 값 변경이 불가능하다. val number2 = 10L 초기화되지 않은 val 변수는 처음 딱 1번만 값 할당이 가능하다. val number5: Long number5 = 2 print(number5) 3) 타입 선언 Long 타입 변수를 선언해보자. var number3: Long = 10L 선언과 동시에 초기화하는 경우에는 타입 선언은 생략 가능하다. var number3 = 10L 초기화하지 않은 선언은 타입을 넣어줘야한다. var number4: Long number4 = 1 print(number4) 4) Primi..
수신 객체 지정 람다 수신 객체를 명시하지 않고 람다의 본문 안에서 다른 객체의 메서드를 호출할 수 있게 한다. with 라이브러리 함수 with를 사용하여 어떤 객체의 이름을 반복하지 않고도 그 객체에 대해 다양한 연산을 수행할 수 있다. with 사용 전 /** 매번 result 반복 사용 */ fun alphabet1() : String { val result = StringBuilder() for (letter in 'A'..'Z') { result.append(letter) } result.append("\nNow I know the alphabet!") return result.toString() } fun main() { println(alphabet1()) } with 사용 후 fun al..
코틀린 람다 전달 함수형 인터페이스를 인자로 원하는 자바 메서드에 코틀린 람다를 전달할 수 있다. 자바 void postponeComputation(int delay, Runnable computation); 코틀린에서 람다를 위 함수에 넘겨보자. postponeComputation(1000) { println(42) } 컴파일러는 자동으로 람다를 Runnable 인스턴스(Runnable을 구현한 무명 클래스의 인스턴스)로 변환해준다. 무명 클래스에 있는 유일한 추상 메서드를 구현할 때 람다 본문을 메서드 본문으로 사용한다. Runnable은 run()이 그런 추상 메서드다. Runnable을 구현하는 무명 객체를 명시적으로 만들어서 사용할 수도 있다. 객체 식을 함수형 인터페이스 구현으로 넘긴다. po..
컬렉션의 map, filter 함수 filter, map은 리스트를 반환한다. 이 함수들은 결과 컬렉션을 즉시(eagerly) 생성한다. 이는 컬렉션 함수로 연쇄하면 매 단계마다 계산 중간 결과를 새로운 컬렉션에 임시로 담는다. package chapter5_람다로_프로그래밍._3_지연계산_컬렉션연산 data class Person(val name: String, val age: Int) fun main() { val people = listOf( Person("Alice", 29), Person("Bob", 31) ) val filter = people.map(Person::name).filter{ it.startsWith("김") } } 이는 이 연쇄 호출이 리스트를 2개 만든다는 뜻이다. 한 리스트..
filter 결과 : 입력 컬렉션의 원소 중에서 주어진 술어(참/거짓을 반환하는 함수 : predicate) 를 만족하는 원소만으로 이뤄진 새로운 컬렉션 예제 Person 클래스 선언 data class Person(val name: String, val age: Int) 1) 짝수만 남긴다. fun main() { val list = listOf(1, 2, 3, 4) println(list.filter { it % 2 == 0 }) // 짝수만 남는다. } 2) 30살 이상인 사람만 출력한다. fun main() { val people = listOf(Person("Alice", 27), Person("Bob", 31)) println(people.filter { it.age > 30 }) // 30살..
람다 안에서 로컬 변수 접근 자바 메서드 안에서 무명 내부 클래스를 정의할때 그 메서드의 로컬 변수를 무명 내부 클래스에서 사용할 수 있다. 람다 안에서도 같은 일을 할 수 있다. 람다 안에서도 동일하게 적용할 수 있다. 람다를 함수 안에서 정의하면 함수의 파라미터뿐 아니라 람다 정의의 앞에 선언된 로컬 변수까지 람다에서 모두 사용할 수 있다. forEach문 예제 fun printMessagesWithPrefix(messages: Collection, prefix: String) { messages.forEach { println("$prefix $it") // 람다 내부에서 함수의 "prefix" 변수 사용 } } 호출 fun main() { val errors = listOf("403 Forbidd..
람다식 코드 블록을 함수 인자로 넘기기 함수형 프로그래밍에서는 클래스를 선언하고 그 클래스의 인스턴스를 함수에 넘기는 대신, 함수를 직접 다른 함수에 전달할 수 있다. 람다 식을 사용하면 코드가 더욱 더 간결해진다. 람다 식을 사용하면 함수를 선언할 필요가 없고 코드 블록을 직접 함수의 인자로 전달할 수 있다. 함수에 인자로 넘기면서 바로 람다를 정의하는 경우가 대부분이다. 코틀린의 람다식은 항상 중괄호로 둘러싸여있다. 인자 목록 주변에 괄호가 없다는 사실을 꼭 기억하라. 화살표(->)가 인자 목록과 람다 본문을 구분해준다. 1) 람다식을 변수에 저장해보자. fun main() { // 람다식을 변수에도 저장할 수 있다. val sum = { x: Int, y: Int -> x + y } println(..
Object 키워드 코틀린에서는 object 키워드를 다양한 상황에서 사용하지만, 모든 경우 클래스를 정의하면서 동시에 인스턴스(객체)를 생성한다는 공통점이 있다. object 키워드를 사용하는 여러 상황을 살펴보자. 상황 설명 객체 선언 (object declaration) 싱글턴을 정의하는 방법 중 하나다. 동반 객체 (companion object) 인스턴스 메서드는 아니지만 어떤 클래스와 관련있는 메서드와 팩토리 메서드를 담을때 쓰인다. 동반 객체 메서드에 접근할때는 동반 객체가 포함된 클래스의 이름을 사용할 수 있다. 객체 식은 자바의 무명 내부 클래스 대신 쓰인다. 객체 선언 (object declaration) 1) 객체 선언 : 싱글턴을 쉽게 만들기 코틀린은 객체 선언 기능을 통해 싱글턴(..
모든 클래스가 정의해야하는 메서드 자바와 마찬가지로 코틀린 클래스도 toString, equals, hashCode 등을 오버라이드 할 수 있다. 코틀린은 이런 메서드 구현을 자동으로 생성해줄 수 있다. 자동으로 생성해주기전, 메서드를 직접 구현해보자. toString() 구현 자바처럼 코틀린의 모든 클래스도 인스턴스의 문자열 표현을 얻을 방법을 제공한다. class CustomClient(val name: String, val postalCode: Int) { /* toString */ override fun toString() = "Client(name=$name, postalCode=$postalCode)" } equals() 구현 코틀린에서 == 연산자가 내부적으로 equals를 호출해서 객체를 ..
인터페이스의 프로퍼티 구현 코틀린에서는 인터페이스에 추상 프로퍼티 선언을 넣을 수 있다. interface InterfaceUser { val nickname: String // 추상 프로퍼티 } InterfaceUser 인터페이스를 구현하는 클래스가 nickname 의 값을 얻을 수 있는 방법을 제공해야한다. 인터페이스에 있는 프로퍼티 선언에는 뒷받침하는 필드나 게터 등의 정보가 들어있지 않다. 사실 인터페이스는 아무 상태도 포함할 수 없으므로 상태를 저장할 필요가 있다면 인터페이스를 구현한 하위 클래스에서 상태 저장을 위한 프로퍼티 등을 만들어야한다. 예시 PrivateUser 별명을 저장만 한다. 주 생성자 안에 프로퍼티를 직접 선언하는 간결한 구문을 사용한다. User의 추상 프로퍼티를 구현하고 ..
생성자 자바에서는 생성자를 하나 이상 선언할 수 있다. 코틀린은 주(primary) 생성자와 부(secondary) 생성자를 구분한다. 또한 코틀린에서는 초기화블록(initializer block)을 통해 초기화 로직을 추가할 수 있다. 주 생성자 (primary) 중괄호가 없고 괄호 사이에 val 선언만 존재한다. 클래스 이름 뒤에 오는 괄호로 둘러싸인 코드를 '주 생성자'라고 부른다. class User1(val nickname: String) 위 코드의 실제 로직은 아래와 같다. class User2 constructor(val _nickname: String) { //_nickname : 프로퍼티와 생성자 파라미터를 구분해준다. // 주 생성자는 생성자 파라미터를 저장하고 그 생성자 파라미터에 의..