함수형 프로그래밍의 개념과 조건

TIL·2023년 1월 16일
0

Java (최은빈)

목록 보기
23/27

  • 예전에는 싱글 코어에서 CPU 클럭수 증가, 실행 시간 최적화, Cache 크기 증가시켜 소프트웨어의 싱글 프로세스, 싱글 스레드의 속도가 공짜로 증가함
    => 그러나 전력 소모 및 발열 문제 등으로 단일코어를 통한 CPU 클럭 증가는 현실적으로 향상시키기 어려움
    => 이를 대안으로 코어 수를 늘려서 CPU의 성능을 향상
  • 함수형 프로그래밍은 오래된 개념 이지만,
    최근 CPU 당 코어수(물리적 동시성)를 여러개 늘리는 하드웨어 기술의 성장으로 함수형 프로그래밍이 제공하는 병렬 스레드, 멀티 프로세싱 구현이 가능하여 JAVA8 부터 사용됨
  • for로 객체 돌면서 sum, average, max, min, filter => 함수로 이미 구현되어 사용만 하면됨 (stream)
  • for문 내부적으로 알아서 돌고 특정 조건에 의해 필터링 시킨 결과를 모을 수 있다
public static List<Student> upper(int score) {
    List<Student> list = new ArrayList<>();
    
    // 반복문 돌기
    for (int i = 0; i < studentList.size(); i++) {
        if (studentList.get(i).getScore() > score) {
            liset.add(studentList.get(i));
        }
    
    }
    
    // 함수형 프로그래밍 (알고리즘 짤 필요 없다)
    return studentList.stream()
            .filter(s -> s.getScore() > socre)
            .sorted(Comparator.comparint(Student::getScore)
            .collect(Collectors.toList());
}



함수의 순수성

  • 어느 곳이든 동일한 인자면 동일한 값이 나와야 한다.
  • 람다 내부에서 밑의 해당사항이 있을 경우 함수의 순수성이 깨질 수 있다. (외부 리소스 접근)
    • lambda 하나당 하나의 Thread 배정 받음. 외부 Main Thread에 할당된 변수를 내부 lambda1, lambda2 에서 수정하면 어느 Thread에서 먼저 접근할지 모름
      • final 상수만 람다식에서 사용 가능 (effective final by compiler)
    • 콘솔 출력도 Java(JVM)가 외부 Console(OS)에 데이터 전달(통신) 이므로 람다 내부에 있으면 안됨
    • 예외 발생
    • 파일 입출력
  • 함수의 순수성 지키기 위해 대부분의 내부 변수 final
public static void main(String[] args) {
    Func func = i -> i + 10;
    
    System.out.println(func.method(1)); // 11
    System.out.println(func.method(1)); // 11 // 12 이면 안됨
    System.out.println(func.method(1)); // 11
}
// 메인 스레드에 할당된 변수
        // 초기화 후 수정 안하면 컴파일러가 final 처리 (effectively final)
        int num = 10;
        System.out.println("num = " + num);

        // 람다에서 외부 변수 사용
        Runnable runnable1 = () -> System.out.println("runnable1 = " + num);
        Runnable runnable2 = () -> System.out.println("runnable2 = " + num);
        runnable1.run();
        runnable2.run();

        // 외부 변수가 수정되면 람다 사용 불가 (컴파일 에러)
//        num++;



함수는 일급이며 고차일 수 있음

  • 함수형 프로그래밍 구현 하려면 함수가 일급객체 이면서
    • 함수가 변수에 들어갈 수 있는 형태
  • 고차함수 여야 한다.
    • 함수의 인자로 함수를 전달하거나 함수가 함수를 반환하는 형태
public class Main {
    public static void main(String[] args) {
        Func func = s -> System.out.println(s); // 함수를 변수로 저장
        func.method("this is functional interface");
    }
}
public class Main {
    public static void main(String[] args) {
        List<Integer> values = Arrays.asList(7, 5, 123, 5, 42, 95, 68, 30, 42);

        List<Integer> result = values.stream()
                .filter(number -> number < 50) // 함수의 인자로 함수를 전달
                .distinct()
                .sorted(Integer::compare)
                .collect(Collectors.toList());

        System.out.println("result = " + result);
    }
}



변수의 불변

  • 초기화된 변수를 수정할 수 없음
  • 새 변수를 잘 만들 수 있지만 기존 변수를 수정할 수는 없음
  • 프로그램 실행 시간 동안 상태를 유지하는 데 도움



함수의 참조 투명성

public class GoodCode {
    public int add() {
        return 3 + 5;
    }
    public static void main(String[] args) {
        new GoodCode().add(); // 8
        new GoodCode().add(); // 8

				// ....

				new GoodCode().add(); // 8 
    }
}
  • 어디에서나 전체 함수 호출을 반환 값 8로 쉽게 바꿀 수 있으므로 함수는 참조적으로 투명

public class BadCode {
    public void print() {
        System.out.println("hello world.");
    }

    public static void main(String[] args) {
        new BadCode().print();
    }
}
  • 무효 함수이므로 호출될 때 아무 것도 반환하지 않음
  • 이 함수는 콘솔에 출력하여 콘솔의 상태를 변경하므로 참조적으로 투명하지 않음

0개의 댓글

관련 채용 정보