본문 바로가기
프로그래밍 기초/JAVA

[Java8] 함수형 프로그래밍

by junsday 2017. 6. 20.

함수형 프로그래밍(Functional Programming)이란?


계산을 수학적 함수의 평가로 취급하고 상태와 가변 데이터를 멀리하는 프로그래밍 패러다임이다.

*Side Effect(부수효과)를 제거할 경우에 프로그램의 동작을 이해하고 예측하는 것이 훨씬 쉬워지기 때문에 Side Effect가 없는 Pure Function(순수 함수)들로만 작성 되어진다.


*Side Effect(부수효과)란?

- 변수를 수정하거나, 객체의 필드를 설정하는 것

- 예외(Exception)를 던지거나 오류를 내면서 실행을 중단하는 것

- 콘솔에 출력하거나 사용자의 입력을 읽어 들이는 것

- 파일에 기록하거나 파일에서 읽어 들이는 것



함수형 프로그래밍(Functional Programming)의 기본 원리들


1. 변경 불가능한 값을 이용

- 함수의 계산을 수행하는 동안 변수에 할당된 값들이 절대로 변하지 않는다.

- 변수에 새로운 값을 설정할 수 있을 뿐이며 일단 값이 설정되면 그 값을 바꿀 수 없다.


2. 함수가 1등 시민 ( First-class )

- 함수가 1등 시민이라는 말은 함수를 변수나 자료구조 안에 담을 수 있고, 함수를 인자로 전달할 수 있으며, 반환 값으로 사용할 수 있다는 의미이다.


3. 람다와 클로저 ( Lambda & Clojure )

- 람다는 익명함수를 말하며, 인수의 리스트와 함수의 본문만을 가지는 함수이다.

- 클로저란 자신이 생성될 때의 scope에서 알 수 있었던 변수를 기억하는 함수이다.


4. 고계함수 ( Higher-order Function )

- 고계함수는 다른 함수를 인수로 받아들이거나 함수를 리턴하는 함수를 가리킨다.

- 함수가 정수와 동등한 값으로 다뤄지기 때문에 함수를 인자로 넘기거나 결과 값을 함수로 반환 받을 수 있다.



함수형 프로그래밍(Functional Programming)의 컨셉


1. 변경 가능한 상태를 불변상태(Immutable)로 만들어 Side Effect를 없애자.

함수 안에서 상태를 관리하고 상태에 따라서 결과 값이 달라지면 안된다는 의미. 상태를 사용하지 않음으로 Side Effect를 차단할 수 있다.


2. 모든 것은 객체이다.

클래스 외에 함수 또한 객체이기 때문에 함수를 값으로 할당할 수 있고, 파라미터로 전달 및 결과 값으로 반환이 가능하다. 이 세 가지 조건을 만족하는 객체를 1급 객체(First-Class)라고 한다.


3. 코드를 간결하게, 가독성을 높여 로직에 집중시키자.

Lambda 및 Stream과 같은 API를 통해 *보일러 플레이트(Boiler Plate)를 제거하고, 내부에 직접적인 함수 호출을 통해 가독성을 높일 수 있다.

*보일러 플레이트(Boiler Plate) - 변경 없이 계속하여 재 사용할 수 있는 저작품


4. 동시성 작업을 보다 쉽고 안전하게 구현하자.



Java8의 함수형 프로그래밍(Functional Programming) 지원


1. Functional Interface

함수형 인터페이스란 하나의 abstract 메소드를 가지는 인터페이스이다. 함수형 인터페이스 지정을 위하여 @FunctionalInterface 어노테이션이 도입되었다.


@FunctionalInterface
public interface Runnable{
public abstract void run();
}


2. Lambda

함수형 인터페이스는 람다를 이용하여 인스턴스화 될 수 있다. 화살표의 왼편은 입력이고 오른편은 코드이다. 입력 타입은 추론 가능하기 때문에 선택이다.


(int x, int y) -> {return x + y;}
(int x, int y) -> x + y
(x, y) -> x + y
x-> x * x
()->x
x->{System.out.println(x);}

Runnable r = () -> {System.out.println("Running!");}


3. Method Reference

메소드 참조는 이름을 가진 메소드들에 대한 컴팩트한 람다 표현식이다.


String::valueOf
x -> String.valueOf(x)
Object::toString
x -> x.toString()
x::toString
() -> x.toString()
ArrayList::new
() -> new ArrayList<>()


4. Clojure

람다는 람다 body의 외부에 정의된 non-static 변수 혹은 개체에 접근 가능하다. 이를 Capturing이라고 한다. 람다 표현식은 오직 로컬 변수와 인자로 던져진 감싸진 블록에서만 접근 가능하다.


int x = 5;
return y -> x + y;


5. Stream

java.util.stream 패키지는 값들의 스트림 위에서 함수형 스타일의 동작을 지우너하는 클래스들을 제공한다.

스트림은 먼저 어떤 소스로부터 스트림을 얻, 다음으로 하나 이상의 중간적(intermediate) 작업을 수행한 후, 마지막으로 하나의 최종 종료(final terminal) 작업을 수행한다.


중간 작업 - filter, map, flatMap, peel, distinct, sorted, limit, substream 

최종 종료 작업 - forEach, toArray, reduce, collect, min, max, count, antyMatch, allMatch, noneMatch, findFirst, findArray


int sumOfWeights = blocks.stream()
.filter(b -> b.getColor() == Red)
.mapToInt(b -> b.getWeight())
.sum();


Java8에서 새로 추가된 주요 기능들을 정리하자면 다음과 같은 것들이 있다.

앞으로 당분간 이 여섯 가지 항목을 하나씩 포스팅 해보려고 한다


1. Interface에 default method와 static method 사용이 가능해졌다.

2. Lambda Expression

3. Stream API

4. Time Date 관련 새로운 API

5. Type Annotation / Repeating Annotation

6. Project Nashorn



'프로그래밍 기초 > JAVA' 카테고리의 다른 글

[Java8] Default Method와 Static method  (1) 2017.06.20
쿠키와 세션, 캐시  (0) 2016.10.26
서블릿(Servlet)이란?  (0) 2016.10.26
interface와 abstract class의 차이  (0) 2016.10.26

댓글