본문 바로가기

CS 스터디/모던 자바 인 액션

자바의 변화

자바 개발 키트(Java Development Kit, JDK1.0) - 1996

Java1.1 - 1997

Java7 - 2011

Java10 - 2018.03

Java11 - 2018.09

 

 

 

역사의 흐름

- 자바 역사를 통틀어 가장 큰 변화는 자바 8에서 일어남

- 획기적이고 생산성에 변화

- 자바 10에서는 형 추론과 관련해서 약간의 변화

- 멀티코어 CPU 대중화와 같은 하드웨어적인 변화가 자바8에 영향을 미침

 

 

 

ex) 사과의 무게를 비교해서 목록에서 정렬하는 코드

자바8 이전 ver

Collection.sort(inventory, new Comparator<Apple>() {
	public int compare(Apple a1, Apple a2) {
    	return a1.getWeight().compareTo(a2.getWeight());
    }
)};

자바8 이후 ver

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

-> 자바 8을 이용하면 자연어에 가깝게 간단한 방식으로 코드 구현 가능

 

 

 

Java8 등장 이전

- 랩톱이나 데스크톱에는 듀얼 혹은 쿼드 코어 이상을 지원하는  CPU 내장

- 자바 프로그램은 코어 중 하나만 사용(즉, 나머지 코어는 유후 idle 상태로 두거나, 운영체제나 바이러스 검사 프로그램과 프로세스 파워를 나눠서 사용)

- 자바 8 등장하기 이전에는 나머지 코어를 활용하려면 스레드를 사용하는 것이 좋다고 하였지만,,,,

- 스레드를 사용하면 관리하기 어렵고 많은 문제 발생

- 자바 1.0(스레드와 락, 메모리 모델 지원), 자바5(스레드 풀, 병렬 실행 컬렉션), 자바7(포크/조인 프레임워크)에서 다양한 해결책을 제공했지만, 여전히 개발자가 활용하기 쉽지 않았음

- 자바 8에서는 병령 실행을 새롭고 단순한 방식으로 접근할 수 있는 방법 제공

- 자바 9에서는 리팩티브 프로그래밍이라는 병렬 실행 기법을 지원, RxJava(리액티브 스트림 툴킷)

 

 

 

Java8

- 간결한 코드, 멀티코어 프로세서의 쉬운 활용이라는 2가지 요구사항을 기반

1. 스트림 API

- 데이터베이스 질의 언어에서 표현식을 처리하는 것처럼 병렬 연산을 지원하는 스트림이라는 새로운 API 제공

- 데이터베이스 질의 언어에서 고수준 언어로 원하는 동작을 표현하면, 구현(자바에서 스트림 라이브러리가 이 역할 수행)에서 최적의 저수준 실행 방법을 선택하는 방식으로 동작

- 병렬형 데이터를 표현하고 이들 데이터를 병렬로 처리할 수 있음을 유연하게 보여줌

- 스트림을 사용하면 에러를 자주 일으키며 멀티코어 CPU를 이용하는 방식보다 비용이 훨씬 비싼 키워드 synchronized를 사용하지 않아도 됨

- 스트림 API -> 메서드에 코드를 전달하는 간결기법(메서드 참조와 람다) + 인터페이스의 디폴트 메서드

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

3. 인터페이스의 디폴트 메서드

 

 

 

자바는 왜 변화할까?

- 프로그래밍 언어는 마치 생태계와 닮음

- 새로운 언어가 등장하면 진화하지 않은 기존 언어는 사장됨

ex) 에이다, 알골, 코볼, 파스칼, 델파이, 스노볼

- 시공을 초월하는 완벽한 언어는 없음, 장단점 존재

 

ex) 

C, C++ 

장점 : 작은 런타임 풋프린트 덕분에 운영체제와 다양한 임베디드 시스템에서 인기

단점: 낮은 안정성 때문에 프로그램이 예기치 않게 종료됨, 바이러스 등이 침투할 수 있는 보안 구멍 존재 가능

 

Java, C#

장점 : 비교적 안전

단점 : C, C++에 비해 런타임 풋프린트 큼

 

- 빅데이터(테라바이트 이상의 데이터셋)라는 도전에 직면

-> 멀티코어 컴퓨터, 컴퓨팅 클러스터를 이용해서 빅데이터를 효과적으로 처리할 필요성 발생

    대용량 데이터와 멀티코어 CPU를 효과적으로 활용해야 함

-> 병렬 프로세싱을 활용해야 하는 데, 이전의 자바로는 대응 불가능

 

- 자바 8은 더 다양한 프로그래밍 도구 그리고 다양한 프로그래밍 문제를 더 빠르고 정확하며 쉽게 유지보수할 수 있는 장점 제공

- 자바8에 추가된 기능은 자바에 없던 완전히 새로운 개념이지만 현재 시장에서 요구하는 기능을 효과적으로 제공

 

 

 

 

자바 8 설계의 밑바탕을 이루는 세 가지 프로그래밍 개념

1. 스트림 처리

- 스트림 : 한 번에 한 개씩 만들어지는 연속적인 데이터 항목들의 모임

- 이론적으로 프로그램은 입력 스트림에서 데이터를 한 개씩 읽어 들이며 마찬가지로 출력 스트림으로 데이터를 한 개씩 기록

- 어떤 프로그램의 출력 스트림은 다른 프로그램의 입력 스트림이 될 수 있음

 

ex) 파일의 단어를 소문자로 바꾼 다음에 사전순으로 단어를 정렬했을 때 가장 마지막에 위치한 세 단어를 출력하는 유닉스 프로그램

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

- 유닉스의 cat 명령은 두 파일을 연결해서 스트림을 생성

- tr은 스트림의 문자를 번역

- sort는 스트림의 행을 정렬

- tail -3 스트림의 마지막 3개 행을 제공

- 유닉스 명령행에서는 파이프 "|" 를 이용해서 명령을 연결

- 유닉스에서는 여러 명령(cat, tr, sort, tail)을 병렬로 실행 -> cat이나 tr이 완료되지 않은 시점에서 sort가 행을 처리하기 시작할 수 있음

 

- 자바8에서는 java.util.stream 패키지에 스트림 API가 추가됨 -> Stream<T>

- 기존에는 한 번에 한 항목을 처리 -> 자바8에서는 우리가 하려는 작업을 (데이터베이스 질의처럼) 고수준으로 추상화해서 일련의 스트림으로 만들어 처리 가능

- 스트림 파이프라인을 이용해서 입력 부분을 여러 CPU 코어에 쉽게 할당할 수 있는 부가적 이득 존재

- 스레드라는 복잡한 작업을 사용하지 않으면서도 공짜로 병렬성을 얻을 수 있음

- 자바 8 스트림 API(4장 ~ 7장)

 

 

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

- 코드 일부를 API로 전달하는 기능

- 위 유닉스 예제에서 sort 명령에 파라미터 추가할 수도 있음, 역순 정렬 뿐만 아니라 다양한 정렬 우선순위가 존재 가능 -> 우선순위에 맞도록 sort 메서드에 명령을 내려야 함

- 자바8 이전의 자바에서는 메서드를 다른 메서드로 전달할 방법이 없었음

- Comparator 객체를 만들어서 sort에 넘겨주는 방법도 존재하지만, 너무 복잡하며 기존 동작을 단순하게 재활용한다는 측면에서 맞지 않음 (앞 부분 자바 비교 예제 코드 확인)

- 자바 8에서는 메서드를 다른 메서드의 인수로 넘겨주는 기능 제공 -> 동작 파라미터화

 

 

3. 병렬성과 공유 가변 데이터

- 병렬성을 얻는 대신 무엇을 포기해야 할까? -> 스트림 메서드로 전달하는 코드의 동작 방식을 조금 바꿔야 함

- 스트림 메서드로 전달하는 코드는 다른 코드와 동시에 실행하더라도 안전하게 실행되어야 함

- 보통 다른 코드와 동시에 실행하더라도 안전하게 실행할 수 있는 코드를 만들려면 공유된 가변 데이터에 접근하지 않아야 함

- 공유된 변수나 객체가 있으면 병렬성에 문제 발생 -> 두 프로세스가 공우된 변수를 동시에 바꾸려하면 어떻게 될까?

- 기존처럼 synchronized를 이용해서 공유된 가변 데이터를 보호하는 규칙을 만들 수 있음 (synchronized는 일반적으로 시스템 성능에 악영향 미침)

- 자바 8 스트림을 이용하면 기존의 자바 스레드 API보다 쉽게 병렬성을 활용 가능

- 다중 프로세싱 코어에서 syncrhonized를 사용하면 생각보다 훨씬 더 비싼 대가 필요(다중 처리 코어에서는 코드가 순차적으로 실행되어야 하므로 병렬이라는 목적을 무력화시킴)

 

 

 

자바가 진화해야하는 이유

- 자바는 계속 진화중

ex) 제네릭 등장, List가 List<String> 으로 변화

- 편리함 제공(컴파일을 할 때 더 많은 에러 검출 가능, 리스트의 유형을 알 수 있어 가독성 좋아짐)

- 틀에 박힌 Iterator 대신 for-each 루프 사용 가능

- 기존 값을 변화시키는 데 집중했던 고전적인 객체지향에서 벗어나 함수형 프로그래밍으로 다가섰다는 것이 자바 8의 가장 큰 변화

- 함수형 프로그래밍에서는 우리가 하려는 작업이 최우선시되며 그 작업을 어떻게 수행하는지(ex, 자료구조를 탐색하면서 컴포넌트 수정)는 별개의 문제로 취급

- 극단적으로 전통적인 객체지향 프로그래밍과 함수형 프로그래밍의 완전 상극

- 언어는 하드웨어나 프로그래머 기대의 변화에 부응하는 방향으로 변화해야함

- 자바 8에 추가된 새로운 기능 덕분에 기존에 다른 언어가 담당하던 생태계 영역을 자바 8이 정복하면서 프로그래머에게 더 많은 기회를 열고 있음