코틀린 & Java/코틀린인액션

고차 함수 정의

코딩하는후운 2023. 5. 23. 09:23
반응형

고차 함수 (High order function)

  • 다른 함수를 인자로 받거나 함수를 반환하는 함수

함수 타입

val sum: (Int, Int) -> Int = { x, y -> x+y }
val action: () -> Unit = { println(42) }

함수 타입을 정의하려면 함수 파라미터의 타입을 괄호 안에 넣고, 그뒤에 화살표(→)를 추가한 다음, 반환 타입을 지정하면 된다.

  • 함수타입을 선언할 때는 반환 타입으로 반드시 명시해야 하므로 Unit을 빼먹어서는 안 된다.

반환 타입이 널이 될 수 있는 타입

var canReturnNull: (Int, Int) -> Int? = {x, y -> null}

함수 타입 전체가 널이 될 수 있는 타입

var funOrNull: ((Int, Int) -> Int)? = null

파라미터 이름과 함수 타입

  • 함수 타입에서 파라미터 이름을 지정할 수도 있다.
fun performRequest {
	url: String,
	callback: (code: Int, content: String) -> Unit
}
  • 함수 타입에 인자 이름을 추가하면 코드 가독성이 좋아지고, IDE는 그 이름을 코드 완성에 사용할 수 있다.

인자로 받은 함수 호출

  • 인자로 받은 함수를 호출하는 구문은 일반 함수를 호출하는 구문과 같다.
fun twoAndThree(operation: (Int, Int) -> Int) {
	val result = operation(2,3)
}

인텔리J 아이디어 팁 디버깅할 때 람다 코드 내부를 한 단계씩 실행해볼 수 있는 스마트 스테핑을 제공한다.

자바에서 코틀린 함수 타입 사용

컴파일된 코드 안에서 함수 타입은 일반 인터페이스로 바뀐다.

즉, 함수 타입의 변수는 FunctionN 인터페이스를 구현하는 객체를 저장.

각 인터페이스에는 invoke 메서드 정의가 하나 들어있다.

invoke 메서드 본문에는 람다의 본문이 들어간다.

자바 8 람다를 넘기면 자동으로 함수 타입의 값으로 변환된다.

/* 코틀린 선언 */
fun processTheAnswer(f: (Int) -> Int) {
	println(f(42))
}

/* 자바 8 */
processTheAnswer(number -> number + 1);

/* 자바 8 이전 */
processTheAnswer(
	new Function1<Integer, Integer>() {
		@override
		public Integer invoke(Integer number) {
		}	
	}
)
  • 코틀린 표준 라이브러리에서 가져온 함수를 자바 코드에서 호출할 수 있다. (람다를 인자로 받는 확장함수)
/* 자바 */
List<String> strings = new ArrayList();
strings.add("42");
CollectionKt.forEach(strings, s -> {
	return Unit.INSTANCE;
});

→ 수신 객체를 확장 함수의 첫 번째 인자로 명시적으로 넘겨야 하므로 깔끔하지는 않다.

  • 반환 타입이 Unit인 함수의 경우

코틀린 Unit타입에는 값이 존재 하므로 자바에서는 그 값을 명시적으로 반환해줘야 한다.

파라미터를 함수 타입으로 선언할 때도 디폴트 값을 정할 수 있다.

  • 매번 람다를 넘기게 되면 기본 동작으로도 충분한 경우 함수호출을 불편하게 만들 수 있음.
  • 디폴트 값을 지정하여 해결
355p 8.4
  • 디폴트 값 선언도 = 뒤에 람다를 넣으면 된다.

널이 될 수 있는 함수 타입으로 함수를 받으면 그 함수를 직접 호출할 수 없다.

  • NPE발생할 가능성 있으므로 컴파일 거부
  • 명시적으로 null여부 검사도 방법
fun foo(callback: (() -> Unit)?) {
	if (callback != null) {
		callback()
	}
}
  • invoke도 안전 호출 구문으로 호출할 수있다. callback?.invoke()

함수를 함수에서 반환

  • 함수를 반환하려면 return 식에 람다나 멤버 참조나 함수 타입의 값을 계산하는 식 등을 넣으면 된다.
fun getShippingCostCalculator(delivery: Delivery): (Order) -> Double {
	if(조건) {
		return { order -> 6 + 2.1 * order.itemCount }
	} 
	return { order -> 1.2 * order.itemCount } //함수에서 람다를 반환
}
  • 상태나 다른 조건에 따라 달라질 수 있는 로직이 있을 때 유용

람다를 활용한 중복 제거

  • 코드의 일부분을 복사해 붙여넣고 싶은 경우가 있다면 그 코드를 람다로 만들면 중복을 제거할 수 있다.

 

반응형