일급 객체 란?
보통 자바의 람다 표현식(Lambda Expression)을 배우다 보면 '일급 객체' 라는 단어를 접하게 되는데, 대체 무엇을 말하는 건지 와닿지 않을 것이다.
'일급' 이란 뜻은 일급 시민 처럼 무슨 혜택을 받는 다는 뜻이 아니라, 사용할 때 다른 요소들과 아무런 차별이 없다는 것을 뜻한다.
그리고 보통 일급 객체를 아래 3가지 조건을 충족한 객체를 일컫는다.
- 모든 일급 객체는 변수나 데이터에 담을 수 있어야 한다.
- 모든 일급 객체는 함수의 파라미터로 전달 할 수 있어야 한다.
- 모든 일급 객체는 함수의 리턴값으로 사용 할수 있어야 한다.
일급 객체는 어떠한 특정 언어에 국한되는 문법 단어가 아니다.
프로그래밍 언어론의 개념으로서, 자바나 자바스크립트 외에 다양한 언어가 이 일급 객체 개념을 가지고 있다.
💡TIP
우리가 많이 사용하는 언어중 Javascript, Python이 일급객체 언어이고 c, pascal, c++가 아니라고 보면 된다. (Java는 람다로 지원)
그렇다고 이것이 뭐 좋고 나쁘고 이런 개념은 아니다. 다만 일급 객체의 특성은 특히 함수형 언어들에서 중요한 포인트가 된다.
자바의 메소드와 자바스크립트 함수의 일급 객체
이번에는 Java와 JavaScript 언어의 비교를 통해 이 '일급 객체' 라는 개념을 알아볼 것이다.
자바의 메소드도 결국은 함수인데 왜 이것을 일급 객체라고 부르지 않는 것인지, 자바스크립트의 함수는 왜 일급 객체인지 하나하나 충족 조건을 비교해 알아보자.
1. 변수나 데이터에 담을 수 있어야 한다.
- 생각해 보면 자바의 메소드는 변수에 할당하거나 그럴순 없다.
- 반면에 자바스크립트는 함수 표현식으로 자유롭게 대입이 가능하다.
public class Main {
public static void hello(){
System.out.println("Hello World");
}
public static void main(String[] args) {
Object a = hello; // !! 메서드를 변수에 할당 불가능
}
}
const hello = function() {
console.log("Hello World");
}
2. 함수의 파라미터로 전달 할 수 있어야 한다.
- 역시 자바의 메소드를 메소드 입력값으로 보내는 행위는 불가능하다.
- 반면에 자바스크립트는 콜백 함수 형태로 자유롭게 전달이 가능하다.
public class Main {
public static void hello(){
System.out.println("Hello World");
}
public static void print(Object func) {
func();
}
public static void main(String[] args) {
print((Object) hello) // !! static 메서드를 함수 매개변수로 전달 불가능
}
}
const hello = function() {
console.log("Hello World");
}
function print(func) {
func();
}
print(hello);
3. 함수의 리턴값으로 사용 할수 있어야 한다.
- 역시 자바의 메소드의 리턴값을 메소드 자체를 반환 행위는 불가능하다.
- 반면에 자바스크립트는 클로저(Closure) 기법을 통해 구성할 수 있다.
const hello = function() {
console.log("Hello World");
return function() {
console.log("Hello World 22");
}
}
const hello2 = hello();
hello2();
자바의 람다 함수의 일급 객체
이러한 관점에서 자바의 람다식 혹은 익명 클래스는 변수나 매개변수에 할당할 수 있고, 리턴값으로도 사용할 수있기 때문에 일급 객체의 요건을 충족한다.
1. 변수나 데이터에 담을 수 있어야 한다.
import java.util.function.Consumer;
public class Main {
public static void main(String[] args) {
Consumer<String> c = (t) -> System.out.println(t); // 람다식을 인터페이스 타입 변수에 할당
c.accept("Hello World");
}
}
2. 함수의 파라미터로 전달 할 수 있어야 한다.
import java.util.function.Consumer;
public class Main {
// 메소드 매개변수로 람다 함수를 전달
public static void print(Consumer<String> c, String str) {
c.accept(str);
}
public static void main(String[] args) {
print((t) -> System.out.println(t) ,"Hello World");
}
}
3. 함수의 리턴값으로 사용 할수 있어야 한다.
import java.util.function.Consumer;
public class Main {
public static Consumer<String> hello() {
// 람다 함수 자체를 리턴함
return (t) -> {
System.out.println(t);
};
}
public static void main(String[] args) {
Consumer<String> c = hello();
c.accept("Hello World");
}
}