1. 함수형 프로그래밍 소개
- 함수형 프로그래밍은 기존 사고방식에서 벗어나 새로운 패러다임으로 문제를 해결하는 방식.
- 이 강의의 목표:
- 함수형 프로그래밍의 차이를 이해하기.
- 함수형 프로그래밍의 기본 개념 학습.
2. 첫 번째 섹션 목표
- 주요 학습 개념:
- 스트림(Stream)
- 람다식(Lambda Expression)
- 메서드 참조(Method Reference)
3. 첫 번째 실습: 숫자 리스트 출력
전통적인 접근법 (구조적 프로그래밍)
문제 정의: 숫자 리스트를 생성하고 리스트의 각 숫자를 한 줄씩 출력.
구현 단계:
- 프로젝트 생성: Eclipse에서 Java 프로젝트 생성.
- 프로젝트 이름: functional programming with java
- 클래스 생성: FP01Structured 클래스 생성.
- 메서드: printAllNumbersInListStructured
- 프로젝트 생성: Eclipse에서 Java 프로젝트 생성.
숫자 리스트 생성:
List<Integer> numbers = List.of(12, 9, 13, 4, 6, 2, 4, 12, 15);
향상된 for 루프 사용:
for (int number : numbers) { System.out.println(number); }
출력 결과:
- 숫자 리스트의 각 요소가 콘솔에 한 줄씩 출력됨.
구조적 프로그래밍의 특징:
- 문제 해결 시 "방법"에 초점을 맞춤.
- 루프 방식 결정 후 작업 수행.
5. 다음 단원 예고
- 함수형 프로그래밍으로 동일한 문제를 해결하는 방법 소개.
2.숫자 리스트를 함수형 접근법으로 출력하기
1. 목표
- 숫자 리스트의 모든 숫자를 함수형 접근법으로 출력합니다.
2. 주요 단계
)메서드 이름 변경
- 메서드 이름을 printAllNumbersInListFunctional로 수정합니다.
- Refactor → Rename 기능을 사용.
)리스트를 스트림으로 변환
- numbers.stream()을 호출하여 리스트를 스트림(Stream)으로 변환.
- 스트림은 리스트 요소를 순차적으로 처리할 수 있는 데이터 시퀀스를 생성.
)각 숫자에 수행할 작업 정의
- 각 숫자에 대해 수행할 작업을 지정:
- 여기서는 숫자를 출력.
- 각 숫자에 대해 수행할 작업을 지정:
)출력을 담당할 메서드 작성
print 메서드 생성
private static void print(int number) { System.out.println(number); }
5.메서드 참조를 사용한 동작 정의
- 스트림의 각 요소에 대해 print 메서드를 호출
numbers.stream().forEach(FP01Functional::print);
메서드 참조 문법:
- 클래스명::메서드명
- 여기서는 FP01Functional::print.
6.출력 결과
- 스트림으로 변환된 각 숫자가 print 메서드에 의해 출력.
3.코드 설명
- 리스트를 스트림으로 변환: numbers.stream()
- 동작 정의: forEach 메서드와 메서드 참조(::)를 사용해 동작을 지정.
- 출력 구현: print 메서드로 스트림의 각 요소를 출력.
4. 최종 코드
import java.util.List; public class FP01Functional { public static void main(String[] args) { List<Integer> numbers = List.of(12, 9, 13, 4); printAllNumbersInListFunctional(numbers); } private static void printAllNumbersInListFunctional(List<Integer> numbers) { numbers.stream().forEach(FP01Functional::print); } private static void print(int number) { System.out.println(number); } }
numbers.stream().forEach(number->System.out.println(number));
5. 실행 결과
- 숫자 리스트가 순서대로 출력:
12 9 13 4
3.함수형 접근법과 구조적 접근법 비교 및 코드 간소화
1. 구조적 접근법 (FPStructured)
- 리스트의 숫자 출력:
- 루프를 통해 숫자를 하나씩 출력.
- 짝수만 출력하려면 조건 추가
if (number % 2 == 0) { System.out.println(number); }
리스트를 지역 변수로 추출해 코드 재사용성 향상.
2. 함수형 접근법 (FP01Functional)
기본 코드
- 스트림의 각 요소에 작업을 수행.
- System.out::println으로 출력 간소화
numbers.stream().forEach(System.out::println);
짝수 필터링
- .filter 메서드를 활용해 조건 추가
numbers.stream() .filter(FP01Functional::isEven) .forEach(System.out::println);
스태틱 메서드 활용: isEven 정의
private static boolean isEven(int number) { return number % 2 == 0; }
3. 메서드 참조 및 함수형 스타일의 간소화
- 메서드 참조를 통해 더 간결하게 작성:
- FP01Functional::isEven으로 조건 전달.
- 스트림에서 숫자 필터링 후 출력 작업.
4. 향후 개선 방향
- 람다 표현식 사용:
- isEven 메서드 없이 조건을 바로 작성
numbers.stream() .filter(number -> number % 2 == 0) .forEach(System.out::println);
메서드 정의 없이 코드 단순화 가능.
1)어진 문자열 리스트(교육 과정)를 한 줄씩 출력
List<String> courses = Arrays.asList( "Spring", "Spring Boot", "API", "Microservices", "AWS", "PCF", "Azure", "Docker", "Kubernetes" );
2)스트림으로 변환 후 각 요소 출력
courses.stream() .forEach(System.out::println);
필터 추가
courses.stream() .filter(course -> course.contains("Spring")) .forEach(System.out::println);
필터 조건 추가:
courses.stream() .filter(course -> course.length() >= 4) .forEach(System.out::println);
Spring, Spring Boot, API, Azure, Docker, Kubernetes만 출력.
4. 함수형 프로그램에서 map 사용하기
1. 짝수 숫자의 제곱 출력
private static void printSquareOfEvenNumbers(List<Integer> numbers) { numbers.stream() // 스트림 생성 .filter(number -> number % 2 == 0) // 짝수 필터링 .map(number -> number * number) // 제곱 계산 .forEach(System.out::println); // 결과 출력 }
동작
- stream(): 리스트를 스트림으로 변환합니다. 스트림은 데이터의 흐름을 처리하는 추상화 도구입니다.
- filter(number -> number % 2 == 0): 각 숫자 중 짝수만 필터링합니다.
- map(number -> number * number): 필터링된 짝수 숫자를 제곱합니다.
- forEach(System.out::println): 최종 결과를 출력합니다.
출력 예시
입력 리스트가 [12, 34, 34, 33, 54, 5]라면 짝수는 [12, 34, 34, 54]이고, 제곱값은 다음과 같습니다:
144 1156 1156 2916
2. 4자 이상 문자열 필터링
List<String> courses = List.of( "spring", "spring boot", "api", "Microseverice", "AWS", "PCF", "azure", "docker", "kubernetes" ); courses.stream() .filter(course -> course.length() >= 4) // 문자열 길이가 4 이상인 것만 필터링 .forEach(System.out::println); // 결과 출력
동작
- filter(course -> course.length() >= 4): 각 문자열의 길이가 4 이상인 항목만 필터링합니다.
- forEach(System.out::println): 필터링된 문자열을 출력합니다.
출력 예시
List.of(...)에서 길이가 4 이상인 문자열은 [spring, spring boot, Microseverice, azure, docker, kubernetes]입니다:
spring spring boot Microseverice azure docker kubernetes
3. 문자열과 길이를 함께 출력
courses.stream() .map(course -> course + " " + course.length()) // 각 문자열에 길이를 추가 .forEach(System.out::println); // 결과 출력
동작
- map(course -> course + " " + course.length()): 각 문자열에 해당 문자열의 길이를 결합합니다. 예: "spring" -> "spring 6"
- forEach(System.out::println): 변환된 결과를 출력합니다.
출력 예시
spring 6 spring boot 11 api 3 Microseverice 13 AWS 3 PCF 3 azure 5 docker 6 kubernetes 10
4. 전체 코드 흐름
List<Integer> numbers = List.of(12, 34, 34, 33, 54, 5); // 짝수 숫자의 제곱 출력 printSquareOfEvenNumbers(numbers); List<String> courses = List.of("spring", "spring boot", "api", "Microseverice", "AWS", "PCF", "azure", "docker", "kubernetes"); // 문자열 길이가 4 이상인 항목 출력 courses.stream() .filter(course -> course.length() >= 4) .forEach(System.out::println); // 각 문자열과 해당 문자열의 길이 출력 courses.stream() .map(course -> course + " " + course.length()) .forEach(System.out::println);
요약
- Stream API를 활용하여 데이터 처리를 효율적으로 수행.
- filter: 조건에 맞는 데이터만 추출.
- map: 데이터를 변환.
- forEach: 최종 결과 출력.
5. Optional 클래스 개요
Optional 클래스는 NullPointerException(NPE) 문제를 줄이기 위해 Java 8에서 도입된 컨테이너 클래스입니다.
이는 값이 존재할 수도, 존재하지 않을 수도 있는 상황을 처리하는 데 유용합니다.
배경과 필요성
- NullPointerException은 Java 애플리케이션에서 가장 흔하고 까다로운 예외 중 하나입니다.
- 널 참조는 토니 호어가 ALGOL 언어에서 도입했으며, 이를 "십억 달러짜리 실수"라고 부를 정도로 많은 문제를 일으켰습니다.
- Java에서는 널 사용의 문제를 해결하기 위해 Optional 클래스를 도입했습니다.
Optional의 주요 특징
- 값의 존재 여부 표현:
- 값이 존재하면 해당 값을 포함하고, 값이 없으면 Optional.empty()를 반환합니다.
- 널 대신 Optional 사용:
- Optional은 null을 직접 사용하지 않고, 안전하게 값의 존재 여부를 처리할 수 있습니다.
실습 코드 설명
과일 리스트 생성 및 Optional 활용
리스트 생성
List<String> fruits = List.of("apple", "banana", "mango");
2. b로 시작하는 과일 찾기
Optional<String> optional = fruits.stream() .filter(fruit -> fruit.startsWith("b")) .findFirst();
- stream() 메서드로 리스트를 스트림으로 변환.
- filter로 조건에 맞는 값을 필터링.
- findFirst로 조건에 맞는 첫 번째 값을 가져옴.
3.Optional 상태 확인
System.out.println(optional); // 값이 있으면 Optional[값], 없으면 Optional.empty System.out.println(optional.isEmpty()); // 값이 없으면 true, 있으면 false System.out.println(optional.isPresent()); // 값이 있으면 true, 없으면 false System.out.println(optional.get()); // 값이 있으면 해당 값 반환, 없으면 예외 발생
요 결과
조건을 만족하는 값이 있을 경우:
- Optional[banana] 출력.
- isEmpty(): false.
- isPresent(): true.
- get(): banana.
조건을 만족하는 값이 없을 경우:
- Optional.empty 출력.
- isEmpty(): true.
- isPresent(): false.
- get(): 예외 발생 (NoSuchElementException).
Optional 생성 예시
값이 있는 Optional 생성:
Optional<String> fruit = Optional.of("banana");
2.빈 Optional 생성:
Optional<String> empty = Optional.empty();
Optional 사용의 장점
- NullPointerException 예방: 값이 없을 때 null 대신 Optional.empty()를 반환.
- 명시적 처리: 값을 다룰 때, 존재 여부를 명확히 확인할 수 있음.
- 안정성과 가독성: 코드의 안정성을 높이고, null 체크 로직을 간소화.
댓글 ( 0)
댓글 남기기