본문 바로가기
개발/JAVA

[JAVA] 함수형 프로그래밍

by seopport 2023. 9. 22.
728x90
반응형

들어가기 앞서

JAVA 8 버전부터 함수형 프로그래밍을 지원하기 위해서 람다 (lambda) 와 스트림(stream) 이 되었습니다. 람다와 스트림을 사용하여 함수형 프로그래밍 스타일로 자바 코드를 작성할 수 있습니다. 람다와 스트림 없이도 자바 코드를 작성하는 데에는 어려움이 없지만, 람다와 스트림을 사용하는 가장 큰 이유는 작성하는 코드의 양을 줄일 수 있고, 읽기 쉬운 코드를 만들 수 있기 때문이다.

 

함수형 프로그래밍 이란?

프로그래밍 패터다임 중 하나로, 자료 처리를 수학적 함수의 계산으로 다루는 방식을 의미합니다. 이러한 프로그래밍 스타일은 상태와 가변 데이터를 최소화하고 대신 함수의 응용을 강조합니다. 함수형 프로그래밍은 데이터의 불변성(immutable)을 유지하며, 결과에 관심을 두며 과정보다는 무엇(What)이 실행될 지를 강조합니다.

 

자바에서의 함수형 프로그래밍은 코드의 가독성과 유지보수성을 향상시키며, 병렬 처리와 동시성 문제를 해결하는데 도움을 줍니다. 이러한 특징들은 자바의 강력한 기능 중 하나로 자리 잡았습니다.

 

람다

  • 람다(lambda)는 익명 함수(anonymous function)를 의미한다. 코드를 간결하게 작성하고 함수를 변수에 할당하거나 다른 함수의 인자로 전달하는 데 도움이 됩니다.

 

아래에 람다를 사용하지 않은 예제 코드와 사용한 예제 코드를 비교해봅시다.

 

일반 코드

public interface Calculator {
	int sum(int a, int b);
}

class MyCalculator implements Calculator {
	public int sum(int a, int b) {
    	return a + b;
	}
}

public class Sample {
	public static void main(String[] args) {
    	Calculator mc = new MyCalculator();
        int result = mc.sum(3, 4);
        System.out.println(result); // 7 출력
    }
}

 

람다를 사용한 코드

interface Calculator {
	int sum(int a, int b);
}

public class Sample {
	public static void main(String[] args) {
    	Calculator mc = (int a, int b) -> a + b; // 람다를 적용한 코드
        int result mc.sum(3, 4);
        System.out.println(result); // 7 출력
	}
}

 

람다 함수 및 인터페이스 사용 시, 주의 사항

인터페이스의 메서드가 1개 이상이면 람다 함수를 사용할 수 없다는 점입니다.

interface Calculator {
	int sum(int a, int b);
    int mul(int a, int b); // 컴파일 오류
}

 

@FunctionalInterface 는 인터페이스가 함수형 인터페이스임을 표시하며, 단 하나의 메서드만 가질 수 있게 합니다. 즉 람다 표현식을 사용하기 위해 주로 사용되는 어노테이션입니다. 

@FunctionalInterface
interface Calculator {
	int sum(int a, int b);
    int mul(int a, int b); // @FunctionalInterface 는 두 번째 메서드를 허용하지 않는다.
}

 

스트림(Stream)

  • 데이터가 물결처럼 흘러가면서 필터링 과정을 통해 여러 번 변경되어 반환되기 때문에 이러한 이름을 가지게 되었습니다.
  • 자바 8부터 도입된 스트림 API는 데이터 컬렉션을 처리하는 함수형 스타일의 도구를 제공합니다. 이를 사용하면 데이터를 변환하고 조작하는 작업을 함수로 표현할 수 있으며, 병렬 처리도 지원됩니다.

 

일반 코드

import java.util.*;

public class StreamNo {
    public static void main(String[] args){
        int[] data = {5, 6, 4, 2, 3, 1, 1, 2, 2, 4, 8};

        // 짝수만 포함하는 ArrayList 생성
        ArrayList<Integer> dataList = new ArrayList<>();
        for (int i = 0; i < data.length; i ++) {
            if(data[i] % 2 == 0) {
                dataList.add(data[i]);
            }
        }

        // Set을 사용하여 중복을 제거
        HashSet<Integer> dataSet = new HashSet<>(dataList);

        // Set을 다시 List 로 변경
        ArrayList<Integer> distinctList = new ArrayList<>(dataSet);

        // 역순으로 정렬
        distinctList.sort(Comparator.reverseOrder());

        // Integer 리스트를 정수 배열로 변환
        int[] result = new int[distinctList.size()];
        for (int i = 0; i < result.length; i++){
            result[i] = distinctList.get(i);
        }
    }
}

 

스트림 사용 코드

import java.util.*;

public class StreamYes {
    public static void main(String[] args) {
        int[] data = {5, 6, 4, 2, 3, 1, 1, 2, 2, 4, 8};
        int[] result = Arrays.stream(data) // IntStream 을 생성한다.
                .boxed() // IntStream 을 Stream<Integer> 로 변경한다.
                .filter((a) -> a % 2 == 0) // 짝수를 뽑아낸다.
                .distinct() // 중복을 제거한다.
                .sorted(Comparator.reverseOrder()) // 역순으로 정렬한다.
                .mapToInt(Integer::intValue) // Stream<Integer> 를 IntStream 으로 변경한다.
                .toArray() // int[] 배열로 반환한다.
                ;
    }
}

 

728x90
반응형