728x90
1. 함수형 프로그래밍이란?
(1) 최근 프로그래밍 패러다임과 프로그래밍의 진행
- 명령형 프로그래밍
- 절차지향 프로그래밍 : Top-Down 접근 방식을 통해 순차적으로 진행된다. (C, C++)
- 객체지향 프로그래밍 : Bottom-UP 접근 방식을 통해 세부 모델부터 차근차근 설계하며 진행된다. (C++, Java, C#)
- 선언형 프로그래밍
- ⭐️ 함수형 프로그래밍 : 순수 함수를 조합하며 진행된다. (Haskell, Lisp, Erlang)
명령형 프로그래밍의 고질병인 낮은 가독성과 유지보수의 어려움을 함수형 프로그래밍을 통해 해결할 수 있다.
(2) 함수형 프로그래밍의 특징
⭐️⭐️ 부수 효과가 없는 순수 함수를 1급 객체로 간주하여 파라미터나 반환값으로 사용할 수 있으며, 참조 투명성을 지킬 수 있다.
함수형 프로그래밍의 특징을 위와 같이 한 줄로 요약할 수 있다. (출처 : https://mangkyu.tistory.com/111)
문장의 키워드들을 뜯어보자.
1. ⭐️⭐️ 부수효과란?
- 변수, 자료구조, 객체의 필드 값이 변경되거나 새롭게 설정되는 것.
- I/O 발생
- 예외값 처리
2. ⭐️⭐️ 순수 함수란?
- 부수 효과들을 제거한 함수로 함수의 실행이 외부에 영향을 끼치지 않는 함수를 뜻한다. 함수 자체가 독립적이기에 thread 안정성을 보장 받을 수 있다.
3. ⭐️⭐️ 1급 객체란?
- 변수나 데이터 구조 안에 담을 수 있는 것
- 파라미터로 전달할 수 있는 것
- 반환값으로 사용할 수 있는 것
4. ⭐️⭐️ 참조 투명성이란?
- 동일한 인자에 대해 항상 동일한 결과를 반환하는 것
(3) 함수형 인터페이스과 람다식이란?
Steam API에 대해 알아보기 전 람다식과 함수형 인터페이스에 대해 알아보자.
- ⭐️⭐️ 함수형 인터페이스란?
- 순수 함수와 일반 함수를 다르게 취급하기 위해 함수형 인터페이스 사용한다.
- ⭐️ 함수형 인터페이스는 단 하나의 추상 메서드를 가진다.
- @FunctionalInterface 어노테이션을 통해 함수를 1급 객체처럼 사용할 수 있다.
- ⭐️⭐️ 람다식이란?
- 함수를 하나의 식으로 표현한 것.
- 메소드의 이름이 필요 없는 익명함수이다. (⭐️⭐️⭐️ 익명함수들은 모두 일급 객체이다.)
- 람다식을 통해 불필요한 코드는 줄이고 가독성을 높일 수 있다
- ⭐️⭐️⭐️⭐️⭐️⭐️ 람다식으로 생성된 '순수 함수'는 함수형 인터페이스로만 선언이 가능하다.
- ⭐️ 람다식 내 지역변수는 final이 붙지 않더라도 상수로 간주된다.
- ⭐️ 람다식으로 선언된 변수명은 다른 변수명과 중복 불가하다.
@FunctionalInterface
inteface MathOperation {
// 2개의 정수값이 파라미터로 와서 정수값을 반환해주는 operation 추상 메서드 선언
int operation(int x, int y);
}
public class LambdaExample {
public static void main(String[] args) {
// operation 추상 메서드를 더하는 연산으로 구현하기
MathOperation add = (int x, int y) -> {return x + y;};
int result = add.operation(1, 2);
System.out.println(result);
}
}
2. Streamp API란?
⭐️ 자바 8부터 Streamp API와 람다식, 함수형 인터페이스 등을 지원한다. Stream API는 Java에서도 함수형 프로그래밍을 할 수 있게 데이터를 추상화하고 처리하는데 자주 사용되는 함수들을 정의해두었다.
⭐️⭐️ Stream 연산들의 매개변수가 모든 함수형 인터페이스이다. ⭐️⭐️⭐️ 또한, 함수형 인터페이스의 인스턴스로는 람다식으로 생성된 순수함수가 오는 것이 이상적이다.
- Stream API의 특징
- 원본 데이터 내용을 읽기만 할 뿐 변경하지 않는다.
- 일회용이다. 다시 사용하기 위해서는 Stream을 다시 생성해주어야 한다.
- 내부 반복으로 작업을 처리한다. 반복 문법을 메서드 내에 숨기고 있기에 가독성이 증가한다.
- ⭐️⭐️ Stream API의 연산 단계
- 생성하기
- 가공하기 (중간연산) : 원본 데이터를 별도의 데이터로 가공하여 연산한다. 중간 연산들은 ; 없이 여러 번 연결될 수 있다.
- 결과 만들기 (최종연산) : 가공된 데이터들을 가지고 연산하여 원하는 결과를 만든다.
- ex) 정수 리스트에서 각 원소를 제곱한 값을 출력하는 예제
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class MapExample {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1,2,3,4,5);
// 각 원소를 제곱한 뒤 새로운 리스트를 만들어 반환
List<Integer> squaredNumbers = numbers.stream()
.map(number -> number * number)
.collect(Collectors.toList());
System.out.println(squaredNumbers);
}
}