본문 바로가기
Java/Java 8

[자바 8 함수형 프로그래밍] 일급이란? 일급메서드 그리고 스트림API

by 람쥐 2024. 12. 12.
반응형

목차

  1. 시작하며: 일급 컬렉션에서 '일급'이란?
  2. 메서드도 '일급 시민'이 될 수 있을까?
  3. '일급 메서드'의 필요성
  4. 스트림 API에서 일급 메서드 사용 시 주의할 점
  5. 메서드를 일급으로 다루는 변화: 전통적 코드 vs 자바 8 이후
  6. 로또 미션 적용 예제: 이급에서 일급으로
  7. 결론

시작하며

일급컬렉션에서 '일급' 이란?

프로그래밍 언어의 핵심은 결국 값을 바꾸는 것입니다. 값의 변화는 프로그램의 상태를 바꿔가며, 우리가 원하는 결과를 얻기 위한 핵심적인 과정이죠. 그런데 어떤 요소를 '값'으로 취급할 수 있으며, 어떤 요소를 직접 전달하거나 반환할 수 있을지는 언어 설계에 따라 다릅니다. 자바 8 이전에는 메서드나 클래스를 값으로 직접 전달할 수 없었습니다. 변수나 '일급(First-Class) 컬렉션'과 달리, 메서드나 클래스는 '이급(Second-Class) 시민'으로 취급되었죠. 여기서 일급(First-Class)이라는 표현은 1960년대 미국 시민권 운동에서 비롯된 개념으로, '완전한 자유와 권리를 누릴 수 있는 시민'을 의미합니다. 이를 프로그래밍 언어에 적용하면, 함수나 객체처럼 자유롭게 전달되고 반환될 수 있는 요소가 곧 '일급 시민'인 것입니다.  정리하면, '일급'은 언어 요소가 자유롭게 전달되고 반환될 수 있는 완전한 '값'으로서의 지위를 의미합니다.

 

메서드도 '일급' 일 수 있을까?

전통적인 자바에서는 메서드와 클래스를 값으로 다루지 못했기 때문에, 메서드를 다른 메서드에 전달하려면 인터페이스를 구현하는 익명 클래스나 별도의 객체를 생성하는 우회적인 방법을 사용해야 했습니다. 그러나 자바 8부터는 이 상황이 완전히 바뀌었습니다. 람다(Lambda)와 메서드 참조(Method Reference)가 도입되면서, 이제 메서드 또한 사실상 일급 시민처럼 활용할 수 있게 된 것이죠. 즉, 자바 8의 람다와 메서드 참조 도입으로 메서드 역시 사실상 일급값으로 취급할 수 있게 되었습니다.

스트림 API와 함수형 프로그래밍

'일급메서드' 를 왜 필요로 하는걸까?

그렇다면 일급 시민 대접을 받게 된 메서드는 어디에 활용할 수 있을까요?
대표적인 무대가 바로 자바 8의 스트림(Stream) API입니다. 스트림 API는 함수형 프로그래밍 패러다임을 자바에 본격적으로 도입하고, 병렬성 활용을 획기적으로 개선했습니다. 스트림 파이프라인에 일급 메서드를 활용하면, 입력 데이터를 여러 CPU 코어에 쉽게 분배해 스레드를 복잡하게 다루지 않고도 '공짜'로 병렬성을 얻을 수 있습니다. 기존의 자바 스레드 API를 사용할 때처럼 synchronized나 lock을 관리하는 번거로움이 필요 없으며, 데이터 처리 파이프라인을 훨씬 효율적으로 병렬화할 수 있는 것이죠.

스트림API에서의 일급메서드 사용 주의점

하지만 동시에 중요한 점은, 스트림 메서드로 전달하는 함수가 다른 코드와 병렬로 실행되더라도 안정적으로 동작해야 한다는 것입니다. 즉, 공유된 가변 상태를 가지지 않는 '순수 함수(pure function)'나 '상태 없는 함수(stateless function)'를 인자로 전달해야 합니다.
이러한 함수는 람다나 메서드 참조를 통해 간편하게 표현할 수 있으며, 이를 통해 병렬성 활용 시 공유 변수로 인한 충돌을 피하고, synchronized에 따른 성능 저하를 최소화할 수 있습니다. 결국 '일급' 개념은 단순히 메서드를 값으로 다루는 것에 그치지 않고, 스트림 API와 결합하여 함수형 프로그래밍 스타일병렬 처리 최적화를 구현하는 데 큰 도움을 줍니다. 이제 메서드는 일급값처럼 자유롭게 전달되고 결합되며, 더욱 명확하고 유연한 코드 구조를 갖출 수 있습니다.

메서드를 값(이급 -> 일급)으로 다루는 변화

전통적 코드 vs. 자바 8 이후

자바 8 이전에는 숨겨진 파일을 필터링하기 위해 다음과 같이 익명 내부 클래스를 사용했습니다.

File\[\] hiddenFiles = new File(".").listFiles(new FileFilter() {  
    @Override  
    public boolean accept(File file) {  
        return file.isHidden();  
    }  
});

(참고 : 모던 자바 인 액션)

 

여기서 파일 숨김 판별 로직을 값으로 전달하기 위해서는 FileFilter 구현체를 별도로 만들어야 했습니다.

하지만 자바 8 이후에는 다음처럼 코드를 단순화할 수 있습니다.

File\[\] hiddenFiles = new File(".").listFiles(File::isHidden);

이미 isHidden이라는 함수는 준비되어 있으므로 자바8의 메서드 참조(::)('이 메서드를 값으로 사용하라'는 의미)를 이용해서 listFiles에 직접 전달할 수 있습니다. 여기서 메서드가 아닌 함수라는 용어를 사용한 사실도 주목하면 좋을 것 같습니다. 기존에 객체 참조(new로 객체 참조를 생성함)이용해서 객체를 이리저리 주고 받았던 것처럼 자바8에서부터는 File::isHidden을 이용해서 메서드 참조를 만들어 전달할 수 있게 됐습니다.

 

한편,

스칼라(Scala)나 그루비(Groovy) 같은 언어에서는 이미 메서드를 일급값으로 활용해 프로그래밍 유연성을 높인다는 사실이 실험적으로 증명되었다고합니다. 자바도 이러한 흐름을 받아들여, 람다와 메서드 참조를 통한 일급 메서드 개념을 도입한 것입니다. 그 결과, 자바 8에서는 메서드 역시 사실상 일급 시민으로 격상되며, 프로그램 구조 설계에 더 큰 자유도와 재사용성을 제공합니다.

로또 미션 적용 예제

이급에서 일급으로

"우아한 테크코스"의 로또 미션을 살펴보면, 로또 번호를 생성하고 당첨 번호를 비교하는 과정에서 일급 메서드를 활용해 코드를 크게 단순화할 수 있습니다. 기존에는 다음과 같이 일치 개수를 찾았습니다.

int count = 0;  
for (int number : pickedNumbers) {  
    if (winningNumbers.contains(number)) {  
        count++;  
    }  
}

이제 자바 8 스타일로 개선하면, 메서드 참조를 이용하여 아래처럼 표현할 수 있습니다.

Set<Integer> winningNumbers = Set.of(1, 3, 5, 7, 9, 11);  
long matchCount = pickedNumbers.stream()  
    .filter(winningNumbers::contains)  
    .count();

winningNumbers::contains라는 메서드를 필터 조건에 값처럼 전달하여, 일치하는 번호 개수를 명확히 드러낼 수 있습니다. 이전과 달리, 메서드 자체가 '이동 가능한 값'으로 스트림 파이프라인 내에서 활용되는 것이죠. 이처럼 메서드를 일급값처럼 다루면 코드 가독성이 높아지고, 유지보수도 쉬워지며, 테스트 코드 작성 또한 편리해집니다. 메서드를 독립적으로 테스트하거나 다른 스트림 파이프라인에 재활용하는 것도 한결 수월해집니다.


결론

프로그래밍 언어에서 어떤 요소를 '값으로 다룰 수 있는지'는 언어 설계의 핵심 철학 중 하나입니다. 자바 8 이후, 람다와 메서드 참조의 도입으로 메서드 역시 사실상 일급 시민에 가까운 위치로 격상되었습니다. 이제 메서드는 단순한 호출 대상이 아닌, 자유롭게 전달 가능한 값입니다. 함수형 프로그래밍 패러다임과 결합해 스트림, 병렬성, 불변 데이터 구조 활용 등 현대적 개발 기법의 기반을 닦을 수 있게 된 것입니다.

로또 미션과 같은 간단한 프로젝트에서도 이러한 이점을 확인할 수 있습니다. 이전보다 훨씬 깔끔하고 명확한 코드로 도메인을 표현할 수 있고, 이를 통해 개발자는 더 선언적이고 유지보수하기 쉬운 코드를 작성할 수 있습니다. 결국, 메서드 일급값화는 개발자에게 더 강력하고 유연한 도구를 제공한다는 것을 알 수 있습니다. 그리고 이러한 메서드의 일급화는 동작파라미터화 방식(아직은 어떻게 실행할 것인지 결정하지 않은 코드 블록) 프로그래밍의 시작이 된다.

 

이 글은 모던 자바 인 액션 책을 읽고 정리한 내용입니다.

반응형