Java - 함수형 인터페이스

코드 리뷰로부터 얻은 값진 수확

Posted by Yan on December 7, 2022

오늘 코드 리뷰 시간에 함수형 인터페이스 사용을 배웠다. 코드를 줄일 수 있는 새로운 방법을 배웠다!

근본적 질문

왜 함수형 프로그래밍이 주목받는가?

2000년대 초반까지는 CPU의 클럭 증가, 실행시간 최적화, cache 크기 증가를 통해 소프트웨어의 싱글 프로게스, 싱글 스레드의 속도가 증가했다. 그러나 전력 소모 및 발열 문제 등으로 단일코어를 통한 CPU 클럭 증가는 현실적으로 향상시키기 어려운 상황에 돌입하게 되었고, 이를 대안으로 코어 수를 늘려서 CPU 성능을 향상하게 되었다.

함수형 프로그래밍이 좋은 이유
1. 불변이라는 것 = 교착상태에 빠지지 않는다
  • 함수형 프로그램은 대입문이 없기 때문에 기본적으로 한 번 값이 변수에 할당 되고 나면 이후에 값이 변경되지 않는다.
  • 부수효과가 발생하지 않기 때문에 표현 식을 어느 때 실행하더라도 문제가 발생하지 않아 참조 투명성을 갖제 된다.
  • 참조 투명성은 멀티코어 프로세스에서 교착상태에 빠지지 않는다는 장점이 있다.
2. 명확하다는 것
  • 함수가 하는 일은 명확하게 정의되기 때문에 코드를 읽을 때 이해하기 쉽다.
  • 함수의 결합을 통한 고차 함수를 사용할 때도 간결하게 표현할 수 있다.
  • 함수를 갑으로 사용할 수도 있다.
  • 익명 함수를 사용할 수도 있다.

함수형 인터페이스 Functional Interface

  • 추상 메소드abstract method를 딱 하나만 가지고 있는 인터페이스
  • @FunctionalInterface 어노테이션을 붙이면 명시적으로 사용할 수 있다.
  • 자바에서 함수형 프로그래밍을 하면 함수를 일급 객체First class object로 사용할 수 있다.

1급 객체는 뭔가?

1급 객체의 조건

  1. 변수나 데이터에 할당할 수 있어야 한다.
  2. 객체의 파라미터로 넘길 수 있어야 한다.
  3. 객체의 리턴값으로 리턴할 수 있어야 한다.

자바스크립트의 일급객체와 다른 점은?

자바스크립트의 1급 객체 first class citizen
  • 1급 객체 : 다른 객체들에게 적용 가능한 연산을 모두 지원하는 객체
    • 예를 들어, (1) 매개변수로 전달되는 것
    • (2) 함수에서 반환되는 것
    • (3) 변수에 할당되는 것 등등
  • 자바스크립트의 함수는 1급 객체이기 때문에 파라미터로 전달될 수 있다.
자바의 1급 객체

자바에서는 함수가 1급 객체에 해당되지 않아서, 변수에 함수를 할당하고 사용할 수 없다.
그러나 자바의 lambda를 사용하면 함수를 1급 객체로 취급하지 않는 자바를 어느정도 보완할 수 있다.
메소드가 1개만 존재하는 인터페이스 또는 클래스를 통해 마치 함수를 전달하는 것 처럼 사용할 수 있기 때문이다.

1급 컬렉션은 또 뭔가?

  • Collection을 Wrapping하면서, 그 외 다른 멤버 변수가 없는 상태

예를 들면,

1
2
3
4
5
6
7
8
9
10
11
public class Person {
    private String name;
    private List<Car> cars;
    // ...
}

public class Car {
    private String name;
    private String oil;
    // ...
}

위의 객체의 콜렉션을 아래와 같이 wrapping 하는 것

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Person {
    private String name;
    private Cars cars;
    // ...
}

// List<Car> cars를 Wrapping
// 일급 컬렉션
public class Cars {
    // 멤버변수가 하나 밖에 없다!!
    private List<Car> cars;
    // ...
}

public class Car {
    private String name;
    private String oil;
    // ...
}

1급 컬렉션의 장점

  1. 하나의 인스턴스에서 비즈니스 로직을 관리할 수 있다.

일급 컬렉션이 없다면, list로 묶어서 처리해야한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void getMoreThanThree() {
  Car aCar = new Car();
  Car bCar = new Car();
  Car cCar = new Car();

  List<Car> cars = new ArrayList<>();
  cars.add(aCar);
  cars.add(bCar);
  cars.add(cCar);

  cars.stream()
    .filter(car -> car.getPosition() > 3)
    .forEach(System.out::println);
}

일급 컬렉션을 만들어 사용한다면 아래와 같이 처리할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Cars {
  private List<Car> cars;

  public Cars(List<Cars> cars) {
    this.cars = cars;
  }

  public List<Cars> getCars() {
    return cars;
  }

  public List<Cars> getCarsOverPosition(int position) {
    return cars.stream()
            .filter(car.getPosition() > position)
            .collect(Collectors.toList());
  }
}
  • 처음에 Car객체를 생성해서 바로 불변 클래스Cars로 관리하면 더 이상 Car가 추가되거나 삭제되지 않으니 빼먹는 실수가 없다
  • 비즈니스 로직도 따로 서비스를 빼서 분리하지 않고 Cars도메인에서 관리할 수 있다.
  1. 리스트 내의 객체의 상태를 동일하게 관리할 수 있다.

같은 비즈니스 로직에 따라 함께 관리할 수 있다.

reference

Java 8 에서 왜 함수형 프로그래밍이 도입되었을까? 함수형 인터페이스와 자바
1급 객체(First-class citizen) 란?
일급 컬렉션 (First Class Collection)의 소개와 써야할 이유
일급 컬렉션을 사용하는 이유
First Class Collection(일급 컬렉션)