Imperative Programming vs Declarative Programming

2025. 3. 19. 02:11Project Reactor

자바에서의 명령형 프로그래밍과 선언형 프로그래밍

소프트웨어 개발에서 명령형 프로그래밍(Imperative Programming)선언형 프로그래밍(Declarative Programming)은 코드를 작성하는 두 가지 주요 패러다임입니다. 자바(Java)에서도 이 두 가지 패러다임을 모두 활용할 수 있으며, 각각의 방식이 가지는 특성과 차이점을 이해하는 것이 중요합니다.

 

1. 명령형 프로그래밍(Imperative Programming)

📌 개념

명령형 프로그래밍은 컴퓨터가 무엇을 어떻게 해야 하는지를 명시적으로 기술하는 방식입니다. 즉, "어떻게(How)" 문제를 해결할 것인지 절차적으로 지시하는 방식이 특징입니다.

이 방식은 개발자가 프로그램의 실행 흐름을 직접 제어하며, 변수 할당, 루프, 조건문 등을 사용하여 데이터를 처리합니다.

 

🔹 특징

  • 절차적(Procedural) 접근: 코드가 실행될 순서를 단계적으로 명시함
  • 상태 변화(State Change) 기반: 변수 값을 변경하며 연산 수행
  • 명확한 제어 흐름(Control Flow) 필요: 반복문(for, while), 조건문(if-else)을 사용

 

🔸 예제: 리스트의 짝수 요소를 필터링한 후 제곱하기

import java.util.ArrayList;
import java.util.List;

public class ImperativeExample {
    public static void main(String[] args) {
        List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
        List<Integer> squaredEvens = new ArrayList<>();

        for (Integer num : numbers) {
            if (num % 2 == 0) { // 짝수인지 확인
                squaredEvens.add(num * num); // 제곱하여 리스트에 추가
            }
        }

        System.out.println(squaredEvens); // [4, 16, 36, 64, 100]
    }
}

✅ 설명

  • for 루프를 사용하여 리스트를 반복하면서 짝수를 찾음
  • 조건문(if)을 사용하여 필터링 수행
  • 새로운 리스트(squaredEvens)에 추가하여 최종 결과를 생성

이 방식은 명확한 실행 순서가 있으며, 데이터가 반복문과 조건문을 거치면서 변환됩니다.

 

2. 선언형 프로그래밍(Declarative Programming)

📌 개념

선언형 프로그래밍은 "무엇(What)"을 해야 하는지에 초점을 맞추는 방식입니다. 실행 순서(How)를 명시적으로 정의하는 대신, 데이터 변환의 목적과 결과에 집중합니다.

이 방식에서는 불변성(Immutable Data)과 함수형 프로그래밍(Function Composition) 개념이 강조됩니다.

 

🔹 특징

  • 목적 지향적(Objective-Oriented): "어떻게"보다는 "무엇을" 해야 하는지 기술
  • 불변성(Immutability): 기존 데이터를 변경하지 않고 새 데이터 반환
  • 함수형 프로그래밍 스타일: Stream API, map, filter, collect 등의 활용

 

🔸 예제: 스트림을 활용한 짝수 필터링 및 제곱 연산

import java.util.List;
import java.util.stream.Collectors;

public class DeclarativeExample {
    public static void main(String[] args) {
        List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

        List<Integer> squaredEvens = numbers.stream()
                .filter(num -> num % 2 == 0)  // 짝수 필터링
                .map(num -> num * num)        // 제곱 연산
                .collect(Collectors.toList()); // 리스트로 수집

        System.out.println(squaredEvens); // [4, 16, 36, 64, 100]
    }
}

✅ 설명

  • stream()을 사용하여 데이터를 선언적 방식으로 변환
  • filter()를 활용하여 짝수만 남김
  • map()을 사용하여 값을 변환(제곱 연산)
  • collect()를 이용해 최종 리스트로 변환

루프와 상태 변경 없이 원하는 작업을 간결하게 표현할 수 있습니다.

 

3. 명령형 vs 선언형 프로그래밍 비교

구분 명령형 프로그래밍 선언형 프로그래밍
접근 방식 어떻게(How) 처리할지 명시 무엇(What)을 해야 하는지 기술
코드 스타일 절차적(Procedural), 단계별 접근 선언적(Declarative), 조합적 접근
상태 관리 변경 가능한 변수 사용 (Mutable) 불변성(Immutability) 강조
제어 흐름 명시적 (for, while, if 사용) Stream API, filter, map 활용
가독성 코드가 길어질 수 있음 간결하고 직관적
함수형 프로그래밍 거의 사용되지 않음 함수형 스타일 적극 활용

 

4. 언제 명령형과 선언형을 사용할까?

명령형 프로그래밍이 적합한 경우

  • 코드가 매우 단순하고 작은 경우
  • 특정 순서를 따라야 하는 경우 (예: 파일 읽기, I/O 연산)
  • 성능이 중요한 저수준 로직(예: 루프 최적화, 직접 메모리 관리)

선언형 프로그래밍이 적합한 경우

  • 데이터 변환이나 집계 작업이 많은 경우 (예: 컬렉션 조작)
  • 코드 가독성을 높이고 유지보수를 쉽게 하고 싶은 경우
  • 병렬 스트림(Parallel Streams) 등을 활용할 경우

 

5. 결론

자바에서는 명령형과 선언형 프로그래밍을 모두 활용할 수 있으며, 각각의 장점과 단점이 존재합니다.

  • 명령형 프로그래밍절차적 제어가 필요한 곳에서 유용하지만, 코드가 길어지고 가독성이 떨어질 수 있습니다.
  • 선언형 프로그래밍스트림(Stream API), 람다 표현식(Lambda Expressions)을 통해 간결하고 유지보수하기 좋은 코드를 작성할 수 있습니다.

현대 자바에서는 선언형 프로그래밍 방식이 선호되는 추세이며, 특히 함수형 프로그래밍 개념을 적극 활용하는 것이 더 효율적인 경우가 많습니다.

 

🔥 결론: 명령형과 선언형의 장점을 적절히 조합하여 최적의 코드 스타일을 선택하는 것이 중요합니다. 🚀

'Project Reactor' 카테고리의 다른 글

Non-Reactive(비반응적) vs. Reactive(반응적): 우유 공장 예제  (0) 2024.11.21
How to read marble diagrams?  (0) 2024.11.20
Reactive Streams  (0) 2024.11.17