함수형 프로그래밍이 잘 이해가 되지 않아서 다시 한번 보기 위해 게시글로 기록함.
[참고]
함수형 프로그래밍은 컴퓨터 프로그래밍의 패러다임 중 하나로, 계산을 수학적인 함수의 평가로 간주하고, 상태 및 가변 데이터를 피하려는 개념을 중심으로 합니다. 함수형 프로그래밍은 명령형 프로그래밍의 대안으로 나타나며, 순수 함수, 불변성, 고계 함수 등의 개념을 중시합니다.
순수 함수 (Pure Functions): 함수형 프로그래밍에서는 함수가 외부 상태에 의존하지 않고 입력에만 의존하는 "순수 함수"를 중요하게 다룹니다. 동일한 입력에 대해서는 항상 동일한 출력을 반환하며, 부작용이 없는 함수를 선호합니다.
불변성 (Immutability): 함수형 프로그래밍에서는 데이터를 변경할 수 없도록 설계하는 것이 일반적입니다. 변수나 데이터의 상태를 변경하는 대신 새로운 값을 생성하거나 복사하여 사용합니다. 이로써 예측 가능하고 안정적인 코드를 작성할 수 있습니다.
고계 함수 (Higher-Order Functions): 함수를 다루는 함수를 "고계 함수"라고 합니다. 함수를 인자로 받거나 함수를 반환하는 함수를 작성할 수 있습니다. 이는 함수의 조립성을 높이고 추상화를 잘 할 수 있게 해줍니다.
불변성의 자료구조: 불변성은 자료구조에서도 중요합니다. 함수형 프로그래밍에서는 불변성을 갖는 리스트, 맵, 세트 등의 자료구조를 사용합니다.
패턴 매칭 (Pattern Matching): 패턴 매칭은 주어진 데이터 구조를 분해하여 각 부분에 대해 다른 동작을 적용하는 기능입니다. 이는 코드의 가독성과 표현력을 향상시킵니다.
람다식 (Lambda Expressions): 함수형 프로그래밍에서는 익명 함수 또는 람다식을 지원합니다. 이는 간결하게 함수를 표현할 수 있게 해주며 고계 함수와의 연동성을 높입니다.
모나드 (Monads): 모나드는 함수형 프로그래밍에서 부작용을 다루기 위한 디자인 패턴입니다. 모나드를 사용하면 부작용을 갖는 코드를 순수한 함수적 방식으로 표현할 수 있습니다.
순수 함수 (Pure Functions): 부작용이 없고 동일한 입력에 대해서 항상 동일한 출력을 반환하는 함수를 강조합니다.
불변성 (Immutability): 데이터를 변경하는 대신 새로운 값을 생성하거나 복사하여 사용하는 것을 선호합니다.
고계 함수 (Higher-Order Functions): 함수를 다루는 함수로, 함수를 인자로 받거나 함수를 반환하는 고계 함수를 활용합니다.
불변성의 자료구조: 변경 불가능한 자료구조를 사용하여 데이터 변경을 방지하고 예측 가능한 동작을 유지합니다.
람다식 (Lambda Expressions): 익명 함수나 람다식을 통해 코드를 간결하게 표현할 수 있습니다.
패턴 매칭 (Pattern Matching): 데이터 구조를 분해하여 다른 동작을 수행하는 기능을 제공합니다.
모나드 (Monads): 부작용을 다루기 위한 디자인 패턴으로, 예측 가능하게 부작용을 통제할 수 있습니다.
장점:
테스트 용이성: 순수 함수와 불변성은 코드의 예측 가능성을 높여 테스트가 더 쉬워집니다.
병렬 처리 및 분산 시스템: 함수형 프로그래밍은 상태 변경이 없어 병렬 처리가 쉽고, 분산 시스템에서의 확장성이 뛰어납니다.
코드의 간결성: 함수형 프로그래밍은 불필요한 상태 관리를 줄여서 코드를 더 간결하게 만듭니다.
디버깅 용이성: 함수형 프로그래밍은 상태 변경이 없어 디버깅이 간편합니다.
단점:
학습 곡선: 명령형 프로그래밍에서 함수형 프로그래밍으로의 전환이 초기에는 어려울 수 있습니다.
성능: 일부 함수형 언어에서는 불필요한 함수 호출로 인한 오버헤드가 발생할 수 있습니다.
람다 표현식 (Lambda Expressions):
// 기존의 익명 내부 클래스 Runnable runnable = new Runnable() { @Override public void run() { System.out.println("Hello, World!"); } };
// 람다 표현식 Runnable lambdaRunnable = () -> System.out.println("Hello, World!");
고계 함수 (Higher-Order Functions):
import java.util.Arrays; import java.util.List; import java.util.function.Function; // public class HigherOrderFunctionExample { public static void main(String[] args) { List<String> words = Arrays.asList("apple", "orange", "banana"); // // 고계 함수: 문자열 길이를 반환하는 함수를 받아서 적용하는 함수 Function<String, Integer> lengthFunction = String::length; // // map 함수를 사용하여 고계 함수를 적용 List<Integer> lengths = map(words, lengthFunction); // System.out.println("Lengths: " + lengths); }
// 고계 함수: 리스트와 함수를 받아서 각 요소에 함수를 적용한 결과 리스트 반환 public static <T, R> List<R> map(List<T> list, Function<T, R> mapper) { return list.stream() .map(mapper) .toList(); } }
불변성 (Immutability):
import java.util.Collections; import java.util.List; // public class ImmutableListExample { public static void main(String[] args) { List<String> mutableList = List.of("apple", "orange", "banana"); // // 불변 리스트 생성 List<String> immutableList = Collections.unmodifiableList(mutableList); // // 이제 immutableList를 변경하려고 하면 예외 발생 // immutableList.add("grape"); // UnsupportedOperationException } }
스트림 API:
import java.util.Arrays; import java.util.List; // public class StreamExample { public static void main(String[] args) { List<String> fruits = Arrays.asList("apple", "orange", "banana"); // // 스트림 API를 사용한 데이터 처리 long count = fruits.stream() .filter(fruit -> fruit.startsWith("a")) .count(); // System.out.println("Count: " + count); } }