*14 함수형 프로그래밍, 람다식, 스트림

목차

    함수형 프로그래밍, 람다식, 스트림

    14.1 함수형 프로그래밍의 소개

    • 자바의 최근 버전은 함수형 프로그래밍과 병렬 처리를 강조하는 방향으로 나가고 있다.

    프로그래밍 패러다임 분류

    • 명령형 프로그래밍 (imperative programming)
      • 절차 지향 언어 (C, FORTRAN)
      • 객체 지향 언어 (C++, Java)
    • 선언적 프로그래밍 (declarative programming)
      • 논리 프로그래밍 (Prolog)
      • 함수형 프로그래밍 (Haskell, Erlang)

    명령형 프로그래밍 방법

    • 정수가 담긴 ArrayList에서 짝수만 추려내는 예시
    public class Imperative {
    	public static void main(String[] args) {
    		List<Integer> list = List.of(12, 3, 16, 2, 1, 9, 7, 20);
    		List<Integer> even = new ArrayList<>();
    
    		// 짝수를 찾는다.
    		for (Integer e : list) {
    			if (e % 2 == 0) {
    				even.add(e);
    			}
    		}
    		// 짝수를 출력한다.
    		for (Integer e : even) {
    			System.out.println(e);
    		}
    	}
    }
    • 명령형 프로그래밍은 작업을 어떻게 수행하느냐를 중시한다.

    함수형 프로그래밍 방법

    • 위의 예제를 다음과 같이 간략하게 작성할 수 있다.
    public class Test {
    
    	public static void main(String[] args) {
    		List<Integer> list = List.of(12, 3, 16, 2, 1, 9, 7, 20);
    		list.stream()
    			.filter(e -> e % 2 == 0)
    			.forEach(System.out::println);
    	}
    
    }
    • stream() : 리스트 안의 원소들을 하나씩 추출하는 메소드
    • filter() : 들어오는 정수 중에서 짝수만 추려냄
    • 메소드 앞에 .이 찍힌 것은 메소드 체이닝 기법
    • forEach() : 는 들어오는 각 정수에 대하여 전달받은 함수 적용
    • System.out::println : 메소드 참조, 함수를 다른 함수로 보내는 방법
    • 선언적 프로그래밍은 해야 할 일에 집중한다.

    왜 함수형 프로그래밍인가?

    • 함수형 프로그래밍은 선언적 프로그래밍 개념을 실제로 구현한 형태이다.
    • 개발자는 부작용 없는 함수를 사용하여, 원하는 작업을 기술하고, 시스템에서 이것을 어떻게 구현할지를 결정한다.
    • 자바에서는 함수형 프로그래밍의 일부를 스트림 API를 이용하여 지원한다.
    • 함수형 프로그래밍은 병렬 처리가 쉽다

    함수란 무엇인가?

    • 함수는 부작용이 있을 수 있다.
      함수가 실행하면서 외부의 변수를 변경한다는 의미
    • 대표적인 예가 Random 클래스의 nextInt()
      호출될 때마다 난수 발생기의 사태가 변경되고 따라서 반환값이 달라진다.
    • 함수형 프로그래밍에서 함수는 순수 함수 (부작용이 없는 함수) 라고 한다.
    • 순수 함수는 스레드에 대하여 안전하고, 병렬적인 계산이 가능하다.
    • 인수만 동일하다면 항상 동일한 결과를 반환한다.

    자바와 함수형  프로그래밍

    • 자바에서 순수 함수로만 프로그램을 작성한다는 것은 어렵다.
    • Scanner 클래스의 nextLine()이나 Random 클래스의 nextInt() 등 사용
    • 자바에서는 순수한 함수형 프로그래밍이라기보다는 함수형 스타일을 지원한다고 해야 한다.
    • 자바에서 코드의 일부라도 함수형 스타일로 만드려면 어떻게 해야 할까?
      • 지역 변수만을 변경 (다른 범위의 변수를 변경하면 안됨)
      • 참조하는 객체는 변경 불가능해야 한다.
      • 함수나 메소드가 예외를 발생시키지 않아야 한다

    객체 지향 프로그래밍과 함수형 프로그래밍

    14.2 람다식

    함수의 1급 시민 승격

    • 기초형의 값이나 객체, 배열 등은 자바에서 1급 시민.
      즉, 모든 연산이 허용된 엔티티를 의미.
      변수에 저장될 수 있고, 함수의 인수가 될수 있고, 함수에서 반환될 수 있다.
    • Java 8에서 함수가 1급 시민으로 승격 되었다.
      즉, 함수가 값이 된 것.
    • 함수가 값이 되면 가능한 것
      • 변수에 저장할 수 있다.
      • 함수를 매개 변수로 받을 수 있다.
      • 함수를 반환할 수 있다.
      • 강력한 스트림 API의 사용이 용이해진다.

    람다식의 필요성

    • "동작 매개 변수화"를 사용하여 코드를 전달하는 것이 코드의 빈번한 요구 사항 변경에 대처하는 데 유용하다.
    • 익명 클래스를 사용하여 코드 블록을 나타내는 것은 만족스럽지 않다

    람다식이란?

    • 나중에 실행될 목적으로 다른 곳에 전달될 수 있는 코드 블록

    람다식 정의

    • (argument) → (body) 구문을 사용하여 작성된다.
    • 매개 변수 a와 b를 받아서 a+b를 계산하여 반환하는 메소드를 람다식으로 정의
    (int a, int b) -> { return a+b; }
    
    // 비교 원래
    public int sum(int a, int b) {
    	return a+b;
    }
    • 람다식은 0개 이상의 매개 변수를 가질 수 있다.
    • 화살표 →는 람다식에서 매개 변수와 몸체를 구분한다.
    • 매개 변수의 형식을 명시적으로 선언할 수 있다. 또는 문맥에서 추정될 수 있다.
      빈 괄호는 매개변수가 없음을 나타낸다.
    • 단일 매개 변수이고 타입은 유추가 가능한 경우에는 괄호를 사용할 필요가 없다.
    • 몸체에 하나 이상의 문장이 있으면 중괄호로 묶어야 한다.

    람다식의 활용

    • 변수에 람다를 할당할 수 있다.
    • 함수 인터페이스의 컨텍스트에서 람다식을 사용할 수 있다.

    1. 이벤트 처리

    // 이전의 방법
    button.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("버튼 클릭!");
        }
    });
    
    // 람다식을 이용한 방법
    button.addActionListener(e -> {
        System.out.println("버튼 클릭!");
    });

     

    2. Runnable 인터페이스 구현

    // 이전의 방법
    new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("스레드 실행");
        }
    }).start();
    
    // 람다식을 이용한 방법
    new Thread(() -> System.out.println("스레드 실행")).start();

     

    3. 배열에서 forEach()와 같은 함수형 프로그래밍 사용 가능

    // 이전의 방법
    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
    for (Integer n : list) {
        System.out.println(n);
    }
    
    // 람다식을 이용한 방법
    List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
    list.forEach(n -> System.out.println(n));

    14.3 동작 매개 변수화

    14.4 함수형 인터페이스

    14.5 메소드 참조

    14.6 스트림 API

    소소제목

    Summary

    Programming

    Java 목차로 돌아가기

     

    'Java > 교재 정리' 카테고리의 다른 글

    13 제네릭과 컬렉션  (1) 2024.06.10
    09 자바 GUI 기초  (0) 2024.05.03
    *16 멀티 스레딩  (1) 2024.05.02
    08 자바 API 패키지, 예외 처리, 모듈  (0) 2024.04.27
    07 추상 클래스, 인터페이스, 중첩 클래스  (0) 2024.04.26