[Java] Java8 설계의 밑바탕 - 병렬성, 가변 데이터, Method 일급 시민화

GilLog·2021년 6월 14일
1

ModernJavaInAction

목록 보기
6/7

🙆‍♂️ import 🙇‍♂️

Modern Java in Action


병렬성과 공유 가변 데이터

Java 8 설계의 세 번째 프로그래밍 개념은 병렬성을 공짜로 얻는다. 이다.

병렬성을 얻기 위해서는 Stream 메소드로 전달하는 코드의 동작 방식을 변경해야 한다.

Stream 메소드로 전달하는 코드는 다른 코드와 동시에 실행하더라도 안전하게 실행 되어야 하는데,

다른 코드와 동시에 실행 하더라도 안전하게 실행 할 수 있는 코드를 위해서는,
공유된 가변 데이터(Shared Mutable Data)에 접근 하지 않아야 한다.

이러한 함수를 Pure, Side-Effect-Fee, Stateless 함수라 부른다.

지금까지는 독립적으로 실행될 수 있는 다중 코드 사본과 관련된 병렬성을 고려했지만,

공유된 변수나 객체가 있으면 병렬성에 문제가 발생한다.

synchronized를 이용공유된 가변 데이터를 보호하는 규칙을 만들 수 는 있지만,
일반적으로 synchronized는 시스템 성능에 악영향을 미친다.

다중 프로세싱 코어에서 synchronized를 사용하면, 다중 처리 코어에서 코드가 순차적으로 실행되어야 하기때문병렬 수행 목적을 무력화 시키면서 생각보다 훨씬 코스트가 커진다.


하지만 Java 8Stream을 이용하면, 기존 Java Thread API 보다 쉽게 병렬성을 활용할 수 있다.

공유되지 않은 가변 데이터(No Shared Mutable Data)와,
Method, Funtion Code를 다른 Method로 전달하는 두 가지 기능
은,

Functional Programming 패러다임의 핵심 사항이다.

반면에 Imperative Programming(명령형 프로그래밍) 패러다임에서는 일련의 가변 상태로 Programm을 정의 한다.

공유되지 않은 가변 데이터 요구사항이란 인수를 결과로 변환하는 기능과 관련된다.

즉, 이 요구사항수학적 함수 처럼 함수가 정해진 기능만 수행하여 겉으로 보이는 다른 부작용은 발생하지 않는 걸 의미한다.

Java가 진화해야 하는 이유

Programming Language는 하드웨어나 Programmer의 기대 변화에 부응하는 방향으로 변화해야한다.

지금까지 Java는 유연하게 진화를 거듭해 왔다.

Generic의 등장과, List에서 List<String> 등으로 컴파일 시점에 더 많은 에러 검출 가능,
List 유형을 바로 알 수 있는 가독성 등의 Java의 변화를 통해 편리함을 누리고 있다.

또 다른 예시로 Iterator 대신 for-each loop를 사용할 수 있게 되어,

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

함수형 프로그래밍에서는 우리가 하려는 작업이 최우선시 되며,

그 작업을 어떻게 수행하는지는 별개의 문제로 취급한다.

Java 8에서 함수형 프로그래밍 도입으로 두 가지 프로그래밍 패러다임의 장점을 모두 활용할 수 있게 되었다.

Java 8에 추가된 새로운 개념

Programming Language에서 Function이라는 용어는 method 특히 static method와 같은 의미로 사용된다.

Java의 함수는 이에 더해 수학적인 함수처럼 사용되며, 부작용을 일으키지 않는 함수를 의미한다.

Java 8 에서는 함수를 새로운 값의 형식으로 추가했다.

멀티코어에서 병렬 프로그래밍을 활용할 수 있는 Stream과 연계될 수 있도록 함수를 만들었기 때문이다.

함수를 값처럼 취급하는 특징에 의해 어떤 장점들이 제공되는지는 아래를 통해 알 수 있다.

Function using like Value

Java에서 조작할 수 있는 값 중 27(int), 3.14(double) 등의 기본 값이 있다.

두 번째로 객체(객체의 참조)도 값이다.
객체 참조는 클래스의 인스턴스를 가르킨다.

예를 들어, abc(String), new Integer(1111)(Integer), new HashMap<Interger, String>(100) (HashMap 생성자 호출) 등으로 객체 참조를 얻을 수 있다.

new 또는 팩토리 메소드나 라이브러리 함수를 이용해서 객체의 값을 얻을 수 있다.

여기서 함수가 필요한 이유는, Programming Language의 핵심은 값을 바꾸는 것이다.

역사적으로나 전통적으로 Programming Language에서이 값을 일급 값, 일급 시민 이라고 지칭한다.


Java에서 다양한 구조체(Method, Class)가 값의 구조를 표현하는 데 도움이 될 수 있다.

하지만 이러한 모든 구조체를 자유롭게 전달할 수는 없다.

이렇게 전달할 수 없는 구조체이급 시민이다.

다시 정리하면, 위에서 언급한 값들은 모두 일급 시민, method, class는 이급 시민이다.

Instance화한 결과가 값으로 귀결되는 Class를 정의할때, method를 아주 유용하게 활용할 수 있지만,
여전히 Method와 Class는 그 자체로 값이 될 수는 없다.

이러한 사실이 중요한지를 묻는다면, 매우 그렇다.

만약 Runtime에 Method를 전달할 수 있다면, 즉 Method를 일급 시민으로 만들면 프로그래밍에 아주 유용하게 활용될 수 있다.

따라서 Java 8 설계자들은 이급 시민일급 시민으로 바꿀 수 있는 기능을 추가했다.

Method to First Class

스칼라, 그루비 같은 언어에서 이미 Method를 일급 값으로 사용하여,

프로그래머가 활용할 수 있게 하는 도구가 다양해지며,

프로그래밍이 훨씬 수월해진다는 사실이 실험을 통해 확인되었다.

이러한 강력한 기능에 익숙해지면 일급 시민이 부족한 다른 언어 사용을 기피하는 현상까지 발생했다.

그래서 Java 8 설계자들Method를 값으로 취급할 수 있게하여 프로그래머들이 더 쉽게 프로그램을 구현할 수 있는 환경이 제공되도록 설계하였다.

Java 8 에서 Method를 값으로 취급할 수 있는 기능Stream 같은 다른 Java 8 기능의 토대를 제공했다.

Method 참조

Method Reference는 Java 8에 추가된 새로운 기능이다.

Method Reference를 예시를 통해 알아보면 아래와 같다.


디렉터리에서 모든 숨겨진 파일을 필터링 한다고 가정하면,

먼저 주어진 파일이 숨겨져 있는지 여부를 알려주는 메소드를 구현해야 할 것이다.

File Class에서 isHidden method를 이미 제공하고 있다.

isHiddenFile Class를 인수로 받아 boolean을 반환하는 함수이다.

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

위 예제 코드는 FileFilter 객체 내부에 위치isHidden의 결과File.listFiles method로 전달하는 방법으로 숨겨진 파일을 필터링 한다.

하지만 위 완성 코드는 단 세 행으로 구성되었지만,
명시적으로 각 행이 무슨 작업을 수행하는지 확인되지 않는다.

File Class에는 이미 isHidden이라는 method가 있는데 굳이 FileFilterisHidden을 칭칭 감싸고 난 후에 FileFilter를 Instance화 해야 한다.

이는 Java 8이 나타나기 전까지 발생했던 일들이다.

Java 8 에서 위 코드는 아래처럼 구현 가능하다.

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

이미 File 안에는 isHidden이라는 함수가 준비되어 있으므로, Java 8의 메소드 참조 ::
(이 Method를 값으로 사용하라! 는 의미)
이용 listFiles에 직접 전달할 수 있다.

Java 8에서는 더이상 Method가 이급 값이 아닌 일급 값이다.

기존 Object Reference(객체 참조, new로 객체 참조를 생성)를 이용해 객체를 다루었던 것 처럼,
Java 8에서는 Method Reference를 통해서 method를 전달할 수 있게 되었다.

profile
🚀 기록보단 길록을 20.10 ~ 22.02 ⭐ Move To : https://gil-log.github.io/

0개의 댓글