모던 자바인 액션 ch.1 정리

Jiin Lee·2022년 12월 14일

모던자바인액션

목록 보기
1/2
post-thumbnail

Ch.1 자바 8,9,10,11: 무슨일이 일어나고 있는가?

자바 8이 나오기 이전은 어땠을까?

역사의 흐름

자바8은 자바 역사 상 가장 큰 변화가 일어났다. 물론 자바 9, 10 에도 변화가 있지만 8만큼 획기적이거나 생산성이 바뀐것은 아니었다. 변화 덕분에 프로그램 구현은 훨씬 쉬워졌다.

아래 코드는 사과 목록을 무게 순으로 정렬하는 코드이다.

Collections.sort(inventory,new Comparator<Apple>(){
	public int compare(int a, int b){
    	return a.getWeight().compareTo(b.getWeight());
    }
});

하지만 이처럼 4줄에 달하는 코드를 자바8이 등장하며 아래와 같은 방식으로 구현할 수 있다.

inventory.sort(comparing(Apple::getWeight));

위 코드에 대한 설명은 앞으로 책에서 설명하게 될 것이다!

  • 하드웨어의 변화
    멀티코어 CPU 대중화와 같은 하드웨어적 변화는 자바8에 영향을 미쳤다.
    자바 8이 등장하기 이전에는 나머지 코어를 활용하려면 스레드를 사용하는 것이 좋다고 조언을 하곤했다. 하지만 스레드를 사용하는 것은 관리하기 어렵고 많은 문제가 발생할 수 있다.
    자바는 이러한 병렬 실행 환경을 쉽게 관리하고 에러가 덜 발생하는 방향으로 진화하려고 노력했다
    자바5, 자바 7에서도 병렬 실행환경을 지원하는 도구들을 도입했다 (예를 들어 스레드 풀, 병렬 실행 컬렉션). 하지만 이는 개발자가 활용하기 쉽지 않았다. 자바8은 병렬 실행을 새롭고 단순한 방식으로 접근하도록 지원한다.

자바 8에서 제공하는 새로운 기술

스트림 API

스트림 API란 데이터베이스 질의언어에서 표현식을 처리하는 것처럼 병렬 연산을 지원하는 API이다.

  • 스트림이란?
    한번에 한 개씩 만들어지는 연속적인 데이터 항목들의 모임이다. 어떤 프로그램의 출력 스트림은 다른 프로그램의 입력 스트림이 될 수 있다.
    자동차 생산 공장에 이를 비유해보자. 자동차 생산 공장 각각의 작업장에서는 자동차를 받아서 수리한 후 다음 작업장에서 다른 작업을 처리할 수 있도록 넘겨준다. 여러 자동차로 구성된 생산 라인을 스트림이라고 이해할 수 있다.

  • 스트림 API의 핵심
    자바8에는 java.util.stream 패키지에 스트림 API가 추가되었다.
    스트림 API의 핵심은 우리가 하려는 작업을 고수준으로 추상화해서 일련의 스트림으로 만들어 처리할 수 있다는 것이다. 또한 스트림 파이프 라인을 이용해서 입력 부분을 여러 CPU 코어에 쉽게 할당할 수 있다. 스레드를 사용하지 않으면서 동시에 공짜로 병렬성을 얻을 수 있다.

스트림API는 '컬렉션을 처리하면서 발생하는 모호함과 반복적인 코드 문제' 그리고 '멀티코어 활용 어려움'이라는 두가짐 문제를 모두 해결했다. 기존의 컬렉션에서는 데이터를 처리할 때 반복되는 패턴이 많았다. 따라서 라이브러리에서 이러한 반복되는 패턴을 제공한다면 좋을 것이라고 아이디어가 나왔다.
반복되는 패턴으로 주어진 조건에 따라 데이터를 필터링 하거나 데이터를 추출하거나 그룹화하거는 기능이 있다.

이제는 컬렉션을 스트림으로 바꾼 후 병렬로 처리하여 다시 리스트로 복원하면 빠르게 데이터를 필터링하고 그룹화할 수 있다.

메서드에 코드 전달하기

자바 8부턴 코드의 일부를 API전달할 수 있다. sort 메소드를 생각해보자.
예를 들어 2013UK0001, 2014US0002.. 등의 형식을 갖는 송장 ID가 있다고 가정하자. 처음 네개 숫자는 연도를, 다음 두 글자는 국가 코드를, 마지막 네개 숫자는 고객ID를 뜻한다. 이제 우리는 이 송장 ID를 고객 ID 혹은 국가 코드 순으로 정렬해야한다. 즉, sort가 고객ID나 국가 코드로 송장ID를 정렬하도록 sort에 따로 코드를 제공해야 한다.
자바 8 이전에는 메서드를 다른 메서드로 전달할 방법이 없었다. 아까 위에서 본 코드 예제처럼 Comparator 객체를 만들어서 sort에 넘겨줄 순 있다. 하지만 자바 8에서는 메서드를 다른 메서드의 인수로 넘겨주는 기능을 제공한다. 이를 바로 동작 파라미터화라고 부른다.

compareUsingCustomerId를 이용해 sort의 동작을 파라미터화 할 수 있다. 동작 파라미터화는 앞으로 더 자세히 설명할 예정이다.

메서드와 람다를 일급 시민으로

  • 일급이란?
    자바 프로그램에서 조작할 수 있는 값을 생각해보자. 첫번째로 int 형식, double 형식 등의 기본값이다. 두번째로 객체도 값이다. 그리고 함수는 이러한 값들을 바꿀 수 있다. 이처럼 함수로 값을 바꿀 수 있는 것을 일급이라고 부른다. 자바 프로그래밍 언어의 다양한 구조체(메서드, 클래스 같은)가 값의 구조를 표현하는 데 도움이 될 수 있다. 하지만 모든 구조체를 자유롭게 전달할 수 는 없다. 이렇게 전달할 수 없는 구조체는 이급이다. 즉, 메서드와 클래스 등은 이급 시민이다. 이들은 그 자체로 값이 될 수 없다.
    자바 8에서는 이급 시민을 일급 시민으로 바꿀 수 있는 기능을 추가했다.

  • 메서드 참조
    아래 코드는 FileFilter 객체 내부에 위치한 isHidden결과를 File.listFiles 메서드로 전달하는 코드이다.

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

FileFilter객체 내부에 위치한 isHidden()결과를 File.listFiles 메서드로 전달했다.
하지만 이제 자바 8에서는 위와 같은 코드를 한줄로 바꿀 수 있다.

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

이제 :: (이 메서드를 값으로 사용하라는 의미) 를 이용하여 listFiles에 메서드를 전달할 수 있다.
따라서 이제 메서드도 이급이 아닌 일급값이 되었다! 기존에 new로 객체 참조를 생성함으로써 객체를 주고받았던 것처럼 File::isHidden을 이용해 메서드를 참조하고 전달할 수 있다.

  • 람다: 익명함수
    자바 8에서는 메서드를 일급값으로 취급할 뿐 아니라, 람다(또는 익명함수)를 포함하여 함수도 값으로 취급한다. 한두번만 사용할 메서드를 매번 정의하는 것은 귀찮은 일이다. 자바8에서는 익명함수 혹은 람다라는 새로운 개념을 이용하여 이 문제를 해결한다.
    Apple 클래스의 리스트에서 모든 녹색 사과를 반환하는 메서드 (isGreenApple)과 특정 무게 이상의 사과를 필터링하는 메서드 (isHeavyApple) 가 있다고 가정해보자.
filterApples(inventory, (Apple a) -> GREEN.equals(a.getColor());

filterApples(inventory, (Apple a) -> a.getWeight() > 150);

람다를 이용하면 위처럼 간결하게 코드를 짤 수 있다. 즉, 한번만 사용할 메서드는 따로 정의할 필요가 없다.

디폴트 메서드

  • 디폴트 메서드란?
    자바 8에서는 인터페이스를 쉽게 바꿀 수 있도록 디폴트 메서드를 지원한다. 디폴트 메서드는 특정 프로그램을 구현하는 데 도움을 주는 기능이 아니라 미래에 프로그램이 쉽게 변화할 수 있는 환경을 제공하는 기능이다.
    인터페이스에 새로운 메서드를 추가한다면 인터페이스의 구현체는 새로 추가된 메서드를 구현해야한다. 현실적으로 언어 설계자들이 컬렉션 인터페이스를 구현한 모든 코드를 책임질 수 없다. 그래서 자바 8은 구현 클래스에서 구현하지 않아도 되는 메서드를 인터페이스에 추가할 수 있는 기능을 제공한다. 디폴트 메서드를 사용하면 기존의 코드를 건드리지 않고 원래의 인터페이스 설계를 자유롭게 확장할 수 있다. default 라는 새로운 키워드를 지원한다.

정리

그 유명한 '모던 자바 인 액션'을 이제서야 읽기 시작했다! 맹목적으로 스트림이 간결하니까 쓰자!! 이게 아니라 스트림 API의 탄생 배경도 알며 자바의 역사를 알게 되니 흥미롭다. 앞으로의 챕터에서도 알게될 자바의 진화(?)가 궁금하다. 그리고 확실히 블로깅을 하니 공부한 것을 내 것으로 만드는 느낌이다ㅎㅎ 앞으로도 열심히 블로깅해야지!!

0개의 댓글