Java는 멀티 패러다임 언어인가?
Java는 멀티 패러다임 언어라고 할 수 있습니다. 특히 Java 8 이후로는 더욱 명확해졌습니다. 초기에는 “순수한” 객체지향 언어를 목표로 했지만, 시간이 지나면서 다양한 프로그래밍 패러다임을 수용하게 되었습니다.
Java가 지원하는 프로그래밍 패러다임
1. 객체지향 프로그래밍 (OOP) - 핵심 패러다임
// 클래스, 상속, 캡슐화, 다형성
public class Animal {
private String name;
public void makeSound() {
System.out.println("Some sound");
}
}
public class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Woof!");
}
}
2. 명령형 프로그래밍 (Imperative)
// 상태 변경과 제어 흐름을 명시적으로 작성
public static int factorial(int n) {
int result = 1;
for (int i = 1; i <= n; i++) {
result *= i; // 상태 변경
}
return result;
}
3. 함수형 프로그래밍 (Functional) - Java 8+
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
public class FunctionalExample {
public static void main(String[] args) {
// 1. 람다 표현식과 고차 함수
Function<Integer, Integer> square = x -> x * x;
Function<Integer, Integer> addOne = x -> x + 1;
// 함수 합성
Function<Integer, Integer> squareThenAdd = square.andThen(addOne);
System.out.println(squareThenAdd.apply(3)); // 10
// 2. 불변성과 순수 함수
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
List<Integer> doubled = numbers.stream()
.map(n -> n * 2) // 원본을 변경하지 않음
.collect(Collectors.toList());
// 3. 함수를 파라미터로 전달
calculate(10, 5, (a, b) -> a + b); // 15
calculate(10, 5, (a, b) -> a * b); // 50
}
static void calculate(int x, int y, BinaryOperator<Integer> operation) {
System.out.println(operation.apply(x, y));
}
}
4. 제네릭 프로그래밍 (Generic)
// 타입 파라미터를 사용한 일반화
public class Box<T> {
private T content;
public void set(T content) {
this.content = content;
}
public T get() {
return content;
}
}
// 제네릭 메서드
public static <T extends Comparable<T>> T findMax(List<T> list) {
return list.stream()
.max(Comparable::compareTo)
.orElse(null);
}
5. 동시성/병렬 프로그래밍 (Concurrent/Parallel)
import java.util.concurrent.*;
public class ConcurrentExample {
public static void main(String[] args) throws Exception {
// CompletableFuture를 사용한 비동기 프로그래밍
CompletableFuture<String> future1 = CompletableFuture
.supplyAsync(() -> fetchDataFromAPI1());
CompletableFuture<String> future2 = CompletableFuture
.supplyAsync(() -> fetchDataFromAPI2());
// 두 작업을 결합
CompletableFuture<String> combined = future1
.thenCombine(future2, (result1, result2) -> result1 + " " + result2);
System.out.println(combined.get());
}
}
6. 반응형 프로그래밍 (Reactive) - 라이브러리 사용
// RxJava 또는 Project Reactor 사용 예제
Flux.just(1, 2, 3, 4, 5)
.filter(n -> n % 2 == 0)
.map(n -> n * 2)
.subscribe(System.out::println);
다양한 패러다임을 혼합한 실제 예제
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.*;
// OOP: 클래스와 인터페이스 정의
interface DataProcessor<T> {
CompletableFuture<List<T>> process(List<T> data);
}
public class HybridExample implements DataProcessor<Integer> {
private final ExecutorService executor = Executors.newFixedThreadPool(4);
@Override
public CompletableFuture<List<Integer>> process(List<Integer> data) {
// 함수형 + 동시성 프로그래밍
return CompletableFuture.supplyAsync(() ->
data.parallelStream() // 병렬 처리
.filter(n -> n > 0) // 함수형: 필터링
.map(this::complexCalculation) // 메서드 참조
.sorted() // 정렬
.collect(Collectors.toList()),
executor
);
}
// 명령형 스타일의 복잡한 계산
private Integer complexCalculation(Integer n) {
int result = n;
for (int i = 0; i < 3; i++) {
result = result * 2 + 1;
}
return result;
}
public static void main(String[] args) throws Exception {
HybridExample processor = new HybridExample();
List<Integer> data = Arrays.asList(1, -2, 3, 4, -5, 6);
// 비동기 처리 시작
CompletableFuture<List<Integer>> future = processor.process(data);
// 콜백 체인 (함수형)
future.thenApply(result -> {
System.out.println("처리 결과: " + result);
return result;
})
.thenAccept(result -> {
// 결과 활용
int sum = result.stream().mapToInt(Integer::intValue).sum();
System.out.println("합계: " + sum);
})
.get(); // 완료 대기
processor.executor.shutdown();
}
}
Java의 멀티 패러다임 특징
장점
- 점진적 도입: 기존 OOP 코드베이스에 함수형 요소를 점진적으로 도입 가능
- 유연성: 문제에 가장 적합한 패러다임 선택 가능
- 생태계: 다양한 스타일의 라이브러리와 호환
한계
- 완전하지 않은 함수형: 불변성이 언어 차원에서 강제되지 않음
- 혼재된 스타일: 여러 패러다임이 섞여 일관성 유지가 어려울 수 있음
- 학습 곡선: 모든 패러다임을 효과적으로 사용하려면 학습이 필요
결론
Java는 “실용적인” 멀티 패러다임 언어입니다. 순수한 함수형 언어(Haskell)나 순수한 객체지향 언어(Smalltalk)와 달리, Java는 실용성을 중시하며 여러 패러다임의 장점을 선택적으로 활용할 수 있게 설계되었습니다. 특히 Java 8 이후로는 현대적인 프로그래밍 패러다임을 적극적으로 수용하고 있어, 진정한 멀티 패러다임 언어로 진화했다고 볼 수 있습니다.