아빠는 개발자

[java] 함수형 프로그래밍(Functional Programming) 은? 본문

Java

[java] 함수형 프로그래밍(Functional Programming) 은?

father6019 2024. 9. 2. 22:10
728x90
반응형

Java에서 함수형 프로그래밍(Functional Programming)은 함수가 일급 시민(First-Class Citizen)으로 취급되고, 불변성(immutability)을 강조하며, 부작용(Side Effect)을 최소화하는 프로그래밍 패러다임입니다. Java 8에서 람다(Lambda)와 스트림(Stream) API가 도입되면서 함수형 프로그래밍을 더 쉽게 활용할 수 있게 되었습니다.

Java에서 이를 활용하는 방법

1. 람다 표현식 (Lambda Expression)

람다는 익명 함수(Anonymous Function)로, 메서드를 간결하게 표현할 수 있습니다. 주로 함수형 인터페이스(Functional Interface)를 구현할 때 사용됩니다.

// 기존 방식 
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("Hello, world!");
            }
        };
// 람다 표현식 
        Runnable runnableLambda = () -> System.out.println("Hello, world!");
    }
 
2. 함수형 인터페이스 (Functional Interface)

함수형 인터페이스는 하나의 추상 메서드만 가지는 인터페이스입니다. @FunctionalInterface 어노테이션을 사용해 명시적으로 정의할 수 있습니다. 대표적인 예로 java.util.function 패키지에 있는 Function, Predicate, Consumer, Supplier 등이 있습니다.

@FunctionalInterface
interface MyFunction {
    void execute();
}

 

3. 메서드 참조 (Method Reference)

메서드 참조는 기존 메서드를 람다처럼 사용할 수 있게 해줍니다.

// 람다 표현식
Function<String, Integer> func = s -> Integer.parseInt(s);
// 메서드 참조
Function<String, Integer> funcRef = Integer::parseInt;
 
4. 스트림 API (Stream API)

스트림은 데이터의 흐름을 처리하는데 사용되며, 함수형 프로그래밍의 주요 개념 중 하나입니다. 컬렉션이나 배열 등의 데이터 소스를 필터링, 매핑, 축소(reduce) 등의 연산을 통해 처리할 수 있습니다.

 
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); 
// 기존 방식
for (int i : numbers) { 
    if (i % 2 == 0) { System.out.println(i); } 
} 
// 함수형 방식 
(Stream API) numbers.stream().filter(i -> i % 2 == 0) .forEach(System.out::println);

5. 고차 함수 (Higher-Order Function)

고차 함수는 함수를 인자로 받거나, 함수를 반환하는 함수입니다. Java에서는 람다와 메서드 참조를 사용해 고차 함수를 쉽게 구현할 수 있습니다.

// 함수를 인자로 받는 메서드
public static void applyFunction(Consumer<String> consumer) {
    consumer.accept("Hello, Functional Programming!");
}

applyFunction(s ->System.out.println(s));

applyFunction(System.out::println);

6. 불변성 (Immutability)

함수형 프로그래밍에서는 상태 변화(즉, 값의 변경)를 피하는 것이 좋습니다. 불변 객체를 사용하고, 상태를 변경하지 않도록 코드를 작성하는 것이 핵심입니다.

// 불변 객체 예시
final String immutableString = "Hello";

7. 순수 함수 (Pure Function)

순수 함수는 동일한 입력에 대해 항상 동일한 출력을 반환하며, 함수 외부의 상태를 변경하지 않는 함수입니다.

public int add(int a, int b) {
    return a + b; // 순수 함수 
}

8. 함수 조합 (Function Composition)

함수를 결합하여 더 복잡한 기능을 수행할 수 있습니다. andThen, compose 메서드를 사용해 함수 조합을 쉽게 할 수 있습니다.

Function<Integer, Integer> multiplyByTwo = x -> x * 2;
Function<Integer, Integer> addThree = x -> x + 3;
Function<Integer, Integer> combinedFunction = multiplyByTwo.andThen(addThree);
System.out.println(combinedFunction.apply(5)); // 결과: 13

9. Optional

Java 8에서 도입된 Optional 클래스는 함수형 스타일로 NullPointerException을 방지하는데 유용합니다.

Optional<String> optionalString = Optional.ofNullable("Hello");
optionalString.ifPresent(System.out::println); // 값이 있을 경우 출력

10. 실용적인 예시

List<String> names = Arrays.asList("John", "Jane", "Tom", "Emily");
List<String> filteredNames = names.stream().filter(name -> name.startsWith("J")).map(String::toUpperCase).collect(Collectors.toList());
System.out.println(filteredNames); // [JOHN, JANE]
 

이렇게 함수형 프로그래밍을 활용하면 코드의 가독성을 높이고, 버그 발생 가능성을 줄이며, 병렬 처리에 유리한 코드 구조를 만들 수 있습니다. Java에서 함수형 프로그래밍을 활용해 코드의 품질을 향상시킬 수 있습니다.

728x90
반응형