일급 객체(First-Class Object)란
다른 객체들에 일반적으로 적용 가능한 연산을 모두 지원하는 객체를 말한다.
즉, 함수(또는 메서드)를 값처럼 변수에 담거나, 인자로 전달하거나, 결과로 반환할 수 있음을 뜻한다.
자바스크립트, 파이썬, 루비처럼 함수 자체가 객체인 언어들은 기본적으로 이 조건을 만족한다.
자바는 원래 일급 객체 개념이 없었지만, Java 8부터 람다(Lambda)와 Function 인터페이스가 도입되면서
함수도 일급 객체처럼 다룰 수 있게 되었다.
import java.util.function.Function;
public class Example1 {
public static void main(String[] args) {
Function<Integer, Integer> square = x -> x * x; // 함수 할당
System.out.println(square.apply(5)); // 25
}
}
→ Function<Integer, Integer> 타입의 변수 square에 람다식을 직접 할당했다.
자바의 Function 인터페이스는 (입력) → (출력) 형태의 함수를 표현한다.
import java.util.function.Function;
public class Example2 {
public static int operate(Function<Integer, Integer> func, int num) {
return func.apply(num);
}
public static void main(String[] args) {
Function<Integer, Integer> square = x -> x * x;
int result = operate(square, 3);
System.out.println(result); // 9
}
}
→ operate()는 함수를 매개변수로 받는 고차함수(Higher-Order Function)이고,
square는 전달인자로 넘겨진 콜백 함수(Callback Function)이다.
import java.util.function.Function;
public class Example3 {
public static Function<Integer, Integer> add(int n) {
return x -> x + n;
}
public static void main(String[] args) {
Function<Integer, Integer> add3 = add(3); // 함수 반환
System.out.println(add3.apply(4)); // 7
}
}
→ 함수(add)가 또 다른 함수를 리턴한다.
이 역시 자바에서의 고차함수 구현이다.
“함수를 인자로 받거나, 함수를 반환하는 함수”
함수형 프로그래밍의 핵심 개념 중 하나로,
로직을 재활용하고 추상화 수준을 높일 수 있게 한다.
자바에서는 Function, Consumer, Supplier, Predicate 등의
함수형 인터페이스(Functional Interface)를 통해 고차함수를 만들 수 있다.
함수형 프로그래밍을 이해하려면
먼저 명령형(imperative) 과 선언형(declarative) 프로그래밍의 차이를 알아야 한다.
| 구분 | 명령형 프로그래밍 | 선언형 프로그래밍 |
|---|---|---|
| 초점 | 어떻게(How) 해결할지 | 무엇을(What) 할지 |
| 대표 언어 | C, Java(전통), Python | SQL, HTML, 함수형 Java |
| 설명 | 상태 변경 중심, 명령 나열 | 상태 불변, 추상화 중심 |
당신은 애인과 함께 레스토랑에 도착했다.
직원에게 이렇게 말할 수 있다.
명령형 방식 : “저기 창가 쪽 자리가 비었네요. 저 자리로 걸어가서 앉을게요.”
선언형 방식 : “두 명 앉을 자리 부탁해요.”
명령형은 “어떻게” 앉을지를 직접 지시,
선언형은 “무엇을 원하는지”만 말한다.
누군가 “OO호텔이 어디죠?”라고 묻는다면?
명령형 방식 : “이 길로 직진하다가 롯데리아에서 우회전, 두 번째 신호에서 좌회전하세요.”
선언형 방식 : “OO호텔은 xx로 xx길 10에 있어요.”
선언형은 구체적인 “과정”이 아니라 “목표 상태”를 말한다.
(호텔까지 가는 방법은 내비게이션이라는 추상화가 대신 수행한다.)
import java.util.Arrays;
import java.util.List;
public class Example4 {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1,2,3,4,5,6,7,8,9,10);
// 명령형 방식
int result1 = 0;
for (int n : numbers) {
if (n % 2 == 0) result1 += n;
}
// 선언형 (함수형)
int result2 = numbers.stream()
.filter(n -> n % 2 == 0)
.mapToInt(Integer::intValue)
.sum();
System.out.println(result1); // 30
System.out.println(result2); // 30
}
}
명령형은 “어떻게 더할지” 하나하나 지시하고,
선언형은 “무엇을 더하고 싶은지”만 기술한다.
Stream 내부가 바로 “내비게이션” 역할을 하는 셈이다.
함수형 프로그래밍(Functional Programming)은 선언형 프로그래밍의 한 형태로,
상태를 직접 변경하지 않고, 순수한 함수를 조합해 프로그램을 구성한다.
| 개념 | 설명 |
|---|---|
| 순수 함수 (Pure Function) | 동일한 입력에 대해 항상 동일한 결과를 반환하며, 외부 상태를 변경하지 않는다. |
| 일급 객체 (First-Class Citizen) | 함수를 변수에 담거나 전달하고, 반환할 수 있다. |
| 불변성 (Immutability) | 데이터의 상태를 직접 수정하지 않고, 새로운 데이터를 생성한다. |
자바는 본래 명령형 언어였지만,
람다식(Lambda) 과 Stream API의 등장으로
함수형 프로그래밍의 장점을 흡수했다.
이제 자바 개발자도 함수를 값처럼 다루는 사고방식을 익히면
더 깔끔하고, 오류에 강한 코드를 작성할 수 있다.
결국 “함수를 데이터처럼 다루는 능력”이
일급 객체의 핵심이며,
함수형 프로그래밍의 시작점이다.