본문 바로가기

Java

Java 8, 9, 10, 11 무슨 일이 일어나고 있는가?

이 포스팅은 Modern Java In Action 의 CH1을 정리한 내용입니다.

 

Java는 거듭 변화해오고 있다. 이러한 변화중에서 가장 획기적이고 생산성이 바뀌는 변화는 언제였을까? 바로 Java 8이 등장했을 때다. Java 8에서 제공하는 새로운 기술을 간단하게 살펴보자.

  • 스트림 API
  • 메서드에 코드를 전달하는 기법
  • 인터페이스의 디폴트 메서드

스트림 API

자바 8은 데이터베이스 질의 언어에서 표현식을 처리하는 것처럼 병렬 연산을 지원하는 스트림이라는 새로운 API를 제공한다. 데이터베이스 질의 언어에서 고수준 언어로 원하는 동작을 표현하면, 구현(자바에서는 스트림 라이브러리가 이 역할을 수행)에서 최적의 저수준 실행 방법을 선택하는 방식으로 동작한다. 즉, 스트림을 이용하면 에러를 자주 일으키며 멀티코어 CPU를 이용하는 것보다 비용이 훨씬 비싼 키워드 synchronized를 사용하지 않아도 된다.

 

메서드에 코드를 전달하는 기법

메서드에 코드를 전달하는 기법을 이용하면 새롭고 간결한 방식으로 동작 파라미터화 (behavior parameterization)을 구현할 수 있다.

 

자바가 거듭 변화하는 이유 - 왜 아직도 자바는 변화하는가?

우리는 완벽한 언어를 원한다. 하지만 현실적으로 그런 언어는 존재하지 않으며 모든 언어가 장단점을 갖고 있다. 예를 들어, C, C++는 프로그래밍 안정성은 부족하지만 작은 런타임 풋프린트(footprint : 메모리 사용량) 덕분에 운영체제와 다양한 임베디드 시스템에서 여전히 인기를 끌고 있다. 하지만 낮은 안정성 때문에 프로그램이 예기치 않게 종료되거나 바이러스 등이 침투 할 수 있는 보안 구멍이 있을 수 있다. 결국 특정 분야에서 인정받는 언어만이 존재할 뿐이고 그 언어들은 경쟁하고 다른 언어를 도태시킨다. 자바는 경쟁 언어를 대신하며 커다란 생태계를 성공적으로 구축했다.

 

자바의 위치

자바는 어떻게 대중적인 프로그래밍 언어로 성장했는가?
객체지향은 1990년대에 두 가지 이유로 각광받았다. 하나는 캡슐화 덕분에 C에 비해 소프트웨어 엔지니어링적인 문제가 훨씬 적다는 점이고, 다른 하나는 객체지향의 정신적인 모델 덕분에 윈도우 95 및 그 이후의 WIMP( 인간 - 컴퓨터 상호작용에서 UI를 의미한다. Windows, Icons, Menus, Pointer) 프로그래밍 모델에 쉽게 대응할 수 있다는 사실이다. 이것은 '모든 것은 객체다'로 요약할 수 있다. 마우스를 클릭하면 핸들러로 메시지가 전송된다(Mouse 객체의 Clicked 메서드가 호출됨).
자바 모델과 자바 코드 애플릿을 안전하게 실행할 수 있었던 초기 브라우저 덕분에 자바가 대학으로 깊숙이 자리 잡을 수 있었다. 후에 졸업생들이 자바를 업계에서 활용하기 시작했다.
(*마이크로소프트의 C#은 자바 형식의 객체지향 모델의 힘을 깊이 있게 검증해주었다.)

프로그래밍 언어 생태계에서 자바는 다양한 임베디드 컴퓨팅 분야를 성공적으로 장악하고 있었다. 하지만 변화의 바람이 불었다. 프로그래머는 빅데이터, 멀티코어, 클러스터를 이용한 처리 등을 할 필요성이 생겼는데 기존 자바로는 충분히 대응할 수 없었다. 이는 생태계의 기후변화와 같다. 새로운 환경에 빠르게 적응하는 새로운 언어가 생기기마련이다.

 

자바는 이러한 프로그래밍 세상의 기후변화에 적응하기 위해 발전해왔고 다양한 기능을 제공한다. 아래의 새 가지 기능을 살펴보자.

 

스트림처리

스트림이란 한 번에 한 개씩 만들어지는 연속적인 데이터 항목들의 모임이다. 이론적으로 프로그램은 입력 스트림에서 데이터를 한 개씩 읽어 들이며 출력 스트림으로 데이터를 한 개씩 기록한다. 즉 어떤 프로그램의 출력 스트림은 다른 프로그램의 입력 스트림이 될 수 있다. 

아래의 예시를 살펴보자

cat file1 file2 | tr "[A-Z]" "[a-z]" | sort | tail -3

이 예제는 파일의 단어를 소문자로 바꾼 다음에 사전순으로 단어를 정렬했을 때 가장 마지막에 위치한 세 단어를 출력하는 프로그램이다.(file1, file2는 한 행에 한 개의 단어를 포함하고 있다고 가정한다.) 유닉스에서는 여러 명령을 병렬로 실행한다. cat이나 tr이 완료되지 않은 시점에서 sort가 행을 처리하기 시작할 수 있다.

 

자바 8에서는 java.util.stream 패키지에 스트림 API가 추가되었다. 앞선 유닉스 명령어 예제처럼 스트림 API는 파이프라인을 만드는 데 필요한 많은 메서드를 제공한다. 스트림 API의 핵심은 기존에 한 번에 한 항목을 처리했던 작업을 (데이터베이스 질의처럼) 고수준으로 추상화해서 일련의 스트림으로 만들어 처리 할 수 있다는 것이다. 이를 이용하면 공짜로 병렬성을 얻을 수 있다!

 

동작 파라미터화로 메서드에 코드 전달하기

코드 일부를 API로 전달하는 기능이다. 앞선 유닉스 예제에서 sort에 파라미터를 추가하고 싶은 사용자도 있을 것이다. 물론 기본적으로 제공하는 역순정렬 등 다양한 기능이 있지만 따로 코드를 제공해서 sort를 하고싶을 수도 있다. (단어의 마지막 글자만 가지고 sort를 하고싶을 땐 어떻게 할까?) 이러한 기능을 이론적으로 동작 파라미터화(behavior parameterization)라고 한다. 후에 자세히 살펴보자.

 

병렬성과 공유 가변 데이터

스트림을 사용하면 '병렬성'을 공짜로 얻을 수 있다. 과연 정말 공짜일까? 아니다. 스트림 메서드로 전달하는 코드의 동작 방식을 조금 바꿔야 한다. 그리고 스트림 메서드로 전달하는 코드는 다른 코드와 동시에 실행하더라 도 안전하게 실행될 수 있어야 한다. 보통 다른 코드와 동시에 실행하더라도 안전하게 실행할 수 있는 코드를 만들려면 공ㅇㅍ된 가변 데이터에 접근하지 않아야 한다. 이러한 함수를 순수(pure) 함수, 부작용 없는(side-effect-free) 함수, 상태 없는(stateless) 함수라 부른다.