[Java] 함수형 프로그밍

이용준·2022년 11월 9일
0

Java

목록 보기
28/29

람다와 스트림을 사용하면 코드의 양 감소 및 읽기 쉬운 코드를 만드는데 유리하다.

람다

람다는 익명 함수(Anonymous functions)을 의미한다.

1) 일반적 코드

먼저 아래의 인터페이스를 보자

interface Calculator{
  int sum(int a, int b);
}  

위 인터페이스를 사용하려면 다음처럼 Calculator 인터페이스를 구현해야 한다.

class MyCalculator implements Calculator{
  public int sum(int a, int b){
    return a+b;
  }
}  

public class Sample{
  public static void main(String[] args){
    MyCalculator mc = new MyCalculator();
    int result = mc.sum(3,4);
    System.out.println(result); // 7출력
  }
}  

2) 람다를 적용한 코드

위 코드를 다음처럼 람다를 적용한 코드로 변경

interface Calculator{
  int sum(int a, int b);
}

public class Sample{
  public static void main(String[] args){
    Calculator mc = (int a, intb) -> a+b;  // 람다 적용
  }
}  

3) 인터페이스 사용시 주의사항

인터페이스의 메서드가 1개 이상이면 람다함수 생성 불가.

interface Calculator{
  int sum(int a, int b);
  int mul(int a, int b); // mul 메서드 추가시 컴파일 에러 발생
}  

따라서 람다 함수로 사용할 인터페이스는 @FunctionalInterface 어노테이션을 사용하는 것이 좋다.

@FunctionalInterface
interface Calculator{
  int sum(int a, int b);
//  int mul(int a, int b); // FunctionalInterface는 두번째 메서드를 허용하지 않는다.
}  

4) 람다 축약

  • (a,b) -> a+b
    • 인터페이스에 이미 입출력 타입 정의되어있으면 입력값의 타입 생략 가능
  • Integer::sum
    • (a,b) -> a+b는 Integer.sum(int a,int b)와 동일해 위와 같이 작성 가능
    • 클래스::메서드 방식으로 구분해 표기

5)람다함수 인터페이스

  • BiFunction 인터페이스 사용해 Calculator 인터페이스 대신 아래처럼 작성 가능

    import java.util.fuction.BiFuncion;
    
    public class Sample{
      public sataic void main(String[] args){
        BiFunction<Integer, Integer, Integer> mc = (a,b) ->(a+b);
        int result = mc.apply(3,4); // sum이 아닌 apply 메서드 적용
        System.out.println(result);
      }
    }  
    • BiFunction<Integer, Integer, Integer>
      • 입력1, 입력2, 출력1을 의미.
      • apply 메서드 호출로 실행
  • 입출력 모두 동일할 경우 BinaryOperator 사용

    import java.util.function.BinaryOperator;
    
    public class Sample{
      public static void main(String[] args){
        BinaryOperator<Integer> mc= (a,b)->a+b;
        int result = mc.apply(3,4);
        System.out.println(result); // 7출력
      }
    }  

2. 스트림

스트림은 "흐름"이라는 의미이며, 데이터가 흐르며 필터링 과저을 통해 여러번 변경/반환되기 때문에 스트림이라는 이름을 갖게 되었다.

  • 주어진 배열에서 짝수만 찾아 중복을 제거한 후 역순으로 정렬하는 프로그램을 작성해보자.
int[] data = {5,6,4,2,3,4,1,1,2,2,,4,8}
----------------------------------------
(출력결과)
int[] result = {8,6,4,2};
  • 스트림 사용전

    import java.lang.reflect.Array;
    import java.util.*;
    
    public class test {
       public static void main(String[] args) {
           int[] data = {5,6,4,2,3,4,1,1,2,2,4,8};
    
           //짝수만 포함하는 ArrayList 생성ㄴ
           ArrayList<Integer> dataList = new ArrayList<>();
           for(int i=0; i<data.length; i++){
               if(data[i]%2==0){
                   dataList.add(data[i]);
               }
           }
           // Set 사용해 중복 제거
           HashSet<Integer> dataSet=new HashSet<>(dataList);
           // Set을 다시 List로 변경
           ArrayList<Integer> distinctList = new ArrayList<>(dataSet);
           //역순으로 정렬
           distinctList.sort(Comparator.reverseOrder());
           // Integer 리스트를 정수 배열로 변환
           int[] result = new int[distinctList.size()];
           for (int i = 0; i < distinctList.size(); i++) {
               result[i] = distinctList.get(i);
           }
           System.out.println(result);
       }
    }
  • 스트림 사용후

    import java.util.*;
    
    public class test {
       public static void main(String[] args) {
           int[] data = {5,6,4,2,3,4,1,1,2,2,4,8};
    
           //짝수만 포함하는 ArrayList 생성
           int[] result = Arrays.stream(data) // Instream 생성
                   .boxed() //Intsteam을 Stream<Integer>로 변경
                   .filter((a)->a%2==0) // 짝수만 선별
                   .distinct() // 중복 제거
                   .sorted(Comparator.reverseOrder()) // 역순 정렬
                   .mapToInt(Integer::intValue) // Stream<Integer>를 InStream으로 변경.
                   .toArray() // int[] 배열로 반환
                   ;
       }
    }
    

위 코드는 다음과 같은 순서로 동작한다.
1. Arrays.stream(data)으로 정수 배열을 IntStream으로 생성
2. .boxed()로 IntStream을 Integer의 Stream으로 변경한다. (Comparator.reverseOrder와 같은 메서드는 원시 타입인 Integer를 사용하기 때문)
3. .filter((a)->a%2==0)로 짝수만 필터링
4. .distinct()로 스트림에서 중복 제거
5. .sorted(Comparator.reverseOrder())로 역순 정렬
6. .mapToInt(Integer::intValue)로 Integer의 Stream을 IntStream으로 변경한다.
(최종적으로 int[]타입 배열을 리턴해야 하기 때문)
7. .toArray()를 호출해 IntStream 배열인 int[] 배열 리턴

profile
뚝딱뚝딱

0개의 댓글