JVM은 함수형 프로그래밍을 어떻게 지원하는가?
한빛미디어 <나는 리뷰어다> 활동을 위해서 책을 제공받아 작성된 서평입니다.
- 원제 : A Functional Approach to Java: Augmenting Object-Oriented Java Code with Functional Principles
- 저자 : Ben Weidig
- 출간 : O’Reilly Media, 2023 / 한빛미디어, 2024
모던한 언어들의 대세에 따라 함수형 프로그래밍이 떠오르면서 ‘Java 에서의 함수형 프로그래밍’ 에 대해서도 적지 않은 관심이 있다. Java 가 지원하는 함수형 인터페이스와 스트림은 이미 널리 쓰이고 있고 이는 Java 언어를 사용하는 개발자라면 익숙한 내용들이다. 이 책은 이것에서 한발 더 나아가 함수형 프로그래밍이란 무엇이고 Java 는 그것을 어떻게 지원하는지, 사용은 어떻게 하고 무엇을 조심해야 하는지 생각하게끔 한다.
이 책은 Java 에서 함수형 프로그래밍 패러다임을 다루기 위한 기법으로 함수형 인터페이스, 레코드 타입, 스트림, 병렬 스트림, 그리고 옵셔널에 대해서 상세하게 다룬다. 단순히 문법에 대한 설명 뿐만 아니라 레코드 타입의 등장 배경, 옵셔널을 잘 사용하는 방법 등 예시와 구현들을 상당히 상세하게 설명하고 있다.
나오는 키워드들이 초보가 보기에 가볍지 않은 만큼 이 책을 보기 위해 상속, 구현 등 Java 8 까지 포함된 기본 문법들은 당연히 잘 알아야 한다. 컬렉션, 제네릭, 제네릭 메소드 그리고 나아가 Java 가 동시성 프로그래밍을 다루는 법에 대해서도 미리 알고 있다면 이 책을 흥미롭게 볼 것이다.
이제 책 속으로 뛰어들 준비는 됐다. ‘함수형 프로그래밍 with 자바’ 는 크게 두 개의 파트로 나눠져있다. 첫번째는 함수형 프로그래밍 패러다임에 대한 소개와 Java 가 어떤 과정을 통해 이 패러다임에 합류하게 됐는지에 대한 설명이다. 두번째는 객체지향과 명령형 프로그래밍 언어인 Java 를 가지고 어떻게 함수형 패러다임을 접목할 수 있는지 기술적인 설명이다.
첫번째 파트에서 함수형 프로그래밍 패러다임을 소개하면서 명령형 프로그래밍을 하는 자바 개발자들을 놀라지 않게 잘 달래준다. 이 책에 관심을 갖고 서평을 볼 정도면 잘 알고 있을 ‘무엇’ 과 ‘어떻게’ 에 대한 접근을 바탕으로 참조 투명성, 불변성, 일급 객체, 함수 합성, Currying function, Lazy evaluation 이 무엇인지 소개한다.
막연하게 알고 있는 함수형 인터페이스 원형인 Function, Consumer, Supplier, Predicate 에 대해서 당연히 용법에 대해서 설명한다. 하지만 대게는 자바가 이렇게 많은 함수형 인터페이스를 가져야 하는 이유에 대해 명쾌한 해석이 없는것에 비해 이 책에서는 Lambda 대수의 개념 설명을 바탕으로 Java 에서 람다 표현을 취급하기 위해 일급 객체가 되어야 하고 그렇기 때문에 인터페이스가 단일 추상 메소드 (Single Abstract Method) 를 가져야 한다고 설명한다. 여기까지 이야기가 나오면 당연하지만 람다 표현식의 변화된 참조에 대해서도 설명한다.
두번째 파트로 가면 첫번째 파트의 함수형 프로그래밍의 개요에서 설명했던 Java 의 함수형 프로그래밍 기법에 대해 더 자세하게 설명한다. Java 가 불변성을 지원하기 위해 사용하는 Unmodifiable collection, final 키워드, record 타입에 대한 설명도 있다.
재미있었던 부분은 Java 는 python 같이 동적 언어들과 달리 Tuple 컬렉션 이 없다. 그래서 Tuple 자료를 다루기 위해 Map<Integer, List<String>>
따위의 상당히 번거로운 자료구조를 만들어야 한다. 강타입인 Java 언어의 특성상 선언은 어쩔수없이 해야하지만, 이 자료구조를 처리하기 위한 코드는 가만히 생각해봐도 번잡스럽기 마련이다. 이 책에서는 함수형 인터페이스의 선언과 스트림의 메소드 체이닝을 적절히 활용해 생각만해도 복잡한 코드를 어떻게 명시적으로 만드는지 예시를 보여준다. 궁금하면 서점에 가서 p.166 페이지를 보길 바란다.
보통 스트림에 대해서 설명하면 map
, filter
, reduce
3개의 연산 타입이나 생성, 중간연산, 최종연산에 대해 간소하게 나오지만 이 책에서는 마블 다이어그램을 기반으로 각 연산 메소드가 어떻게 작동하는지, Spliterator
인터페이스의 특성에 따라 어떻게 병렬 처리를 하는지, 병렬 처리를 할 때 주의해야 할 점은 무엇인지 상세하게 설명한다.
약간 부록의 느낌으로 생각했던 CompletableFuture에 대한 파트도 있다. Java의 비동기 처리를 위한 CompletableFuture 역시 작업을 선언하고 실행하고 결과를 수집하는 함수형 프로그래밍으로 작성된다. 때문에 간략한 문법에 대한 설명만 있을거라 생각했는데 생각보다 비동기 처리에 대한 저자의 고찰이 잘 녹아있어서 흥미롭게 읽었던 부분이였다.
그 외에도 책에서는 다양한 JVM 기법들을 통해 Java 가 함수형 프로그래밍을 지원한다고 설명한다. 일일이 다 적을순 없지만
- 선언형 프로그래밍으로 작성된 코드는 언제 실행되고 결과가 결정되는지 (invokedynamic)
- 높은 아리티의 함수형 인터페이스는 무엇이 있는지 (BiFunctional)
- 자바에서의 함수 합성은 어떻게 구현하는지 (Glue method)
- 람다에서 예외를 어떻게 다루는지 (Try 타입)
위 내용을 포함해 상당히 생각 해볼법한 내용이 많이 등장하기 때문에 함수형 프로그래밍 패러다임에 딱히 관심이 없더라도, Java 와 JVM 에 대해서 관심이 많은 사람이라면 꼭 한번 읽어보면 좋겠다는 생각을 한다.
개인적으로 올해 초는 객체지향 개념을 다시 한번 짚어봤고 지금은 Java 의 Reflection과 동시성 프로그래밍에 대해 또 다시 심도있게 보고 있는데 지금 두개가 끝나고 나면 이 책에 다시 빠져볼까 싶다. 서평단 리뷰라서가 아니라 여러 지식을 줄줄이 한번에 꿰어주는 속시원한 책이였다.
이 책에서 쓰는 자바 기술
- Functional interface 함수형 인터페이스
- Record 레코드
- Stream & Spliterator
- Parallel stream 병렬스트림
- Optional 옵셔널
이 책을 보기 전에 알고 있으면 도움이 되는 지식
- Java 기본 문법
- 컬렉션, 제네릭, 제네릭 메소드
- 스트림 기본 사용법
- 자바 동시성 프로그래밍
한빛미디어 <나는 리뷰어다> 활동을 위해서 책을 제공받아 작성된 서평입니다.