자바와 Kotlin을 통해 일급객체에 대해 설명해보겠다.
(완벽한 말은 아니지만 일단) 자바에서 보통 객체라 함은 클래스이다. 함수는 클래스 안에 속하므로, 객체의 부속품으로써만 존재하였다. 하지만 Kotlin에서는 함수가 객체가 될 수 있다.
따라서 다음과 같은 프로그래밍이 가능하다.
//코틀린의 변수 할당
val number1 = 10
//코틀린의 함수 선언
fun(){
println("Hello World!")
}
//함수를 변수에 할당
val function1 = fun() { println("Hello World!") }
이는 JavaScript에서도 마찬가지로 자주 쓰이는 형태의 문법이다.
Kotlin과 JavaScript에서 이와 같은 문법을 지원하는 이유는, 함수형 프로그래밍을 위해서이기 때문일 것이다. (이 글에서 함수형 프로그래밍에 대해 설명하진 않겠다)
사실 자바에서도 함수를 객체화 시킬 수 있다. 바로 함수형 인터페이스와 이를 표현하는 람다식을 통해서이다.
interface FunctionalInterface{
void fun();
}
psvm{
FunctionalInterface function1 = () -> System.out.println("Hellow World!");
}
여기서는 사실 함수를 객체화시킨 것이 아니라, 함수를 가지고 있는 인터페이스를 객체화 시킨 것이다.(자바에서는 당연히 인터페이스를 객체로 사용한다.)
하지만 코드만 보면 위 코틀린 코드와 같이 함수를 객체화 시킨 것 처럼 보이며, 사실 그런거나 마찬가지라고 볼 수 있다. 바로 그런 용도로 만들어진 것이 함수형 인터페이스와 람다표현식이기 때문이다. (자바가 함수형 프로그래밍을 지원하기 위해 Java 8 버전에 추가된 문법이다.)
일급객체란 다음과 같은 특성을 가진다.
변수에 할당할 수 있다.
다른 함수의 인자로 전달 될 수 있다.
다른 함수의 결과로 리턴 될 수 있다.
그냥 일반적인 객체의 특성이다.
그렇다면 일급객체란 용어가 굳이 왜 사용되는 것일까?
객체로서의 함수를 표현하기 위한 단어라고 생각한다. 이 글의 내용을 통해 알았듯이, 이는 일반적인 객체가 아니기 때문이다.
함수가 일급객체가 됨으로써 생기는 장점이 있다. 바로 고차함수의 사용이 가능하다는 것이다.
고차함수란 위 일급객체의 2번 특성에 따라, 다른 함수를 인자로 받을 수 있는 함수이다.
고차함수의 대표적인 예로, 우리가 자주 쓰는 자바의 Arrays.sort()가 있다.
Arrays.sort(
arr,
(o1, o2) -> { return o1 - o2; } //인자로 함수가 들어감
);
또는 연속해서 데이터를 처리할 수 있는 Stream 문법 역시, 또 하나의 대표적인 예다.
List<Integer> list = List.of(1,2,3,4,5);
list.stream().filter(n -> n <= 3).foreach(n -> System.out.println(n));
그리고 함수가 일급객체가 됨으로써 생기는 또 다른 장점으로 콜백함수라는 것도 가능해진다고 한다. (이건 따로 찾아보자)