개발 일지/Java

함수형 인터페이스 - Supplier와 Consumer

미숫가루설탕많이 2023. 6. 24. 00:01

프로젝트에서 작성한 코드를 리팩토링할 방법을 찾다가 Supplier와 Consumer라는 함수형 인터페이스를 찾게 되었다. 함수형 인터페이스(Functional Interface)는 단일 추상 메서드를 가지고 있는 인터페이스로, 람다식이나 메서드 참조를 활용해서 함수형 프로그래밍을 지원한다.

 

 

 

 

Supplier<T>

 

Supplier<T>는 매개변수가 없고 값을 반환한다. get() 메서드를 호출해서 값을 생성하거나 가져올 수 있다. 일반적으로는 데이터를 생성하거나 외부에서 값을 가져오는 용도로 사용하며, 'Supplier<T> 변수명'으로 선언하고 그에 따른 람다식을 작성하면 된다.

 

예를 들어, Supplier<Integer>는 정수 값을 생성하고 Supplier<String>은 문자열 값을 가져올 수 있다.

 

 

 

 

Consumer<T>

 

Consumer<T>는 매개변수를 받아서 소비한다. accept(T) 메서드를 호출해서 매개변수를 처리하며, 주로 값을 소비하거나 필드에 할당하는 용도로 사용된다. Supplier와 마찬가지로 'Consumer<T> 변수명'으로 선언하고 그에 따른 람다식을 작성하면 된다.

 

예를 들어, Consumer<Integer>는 정수 값을 받아서 출력할 수 있다.

 

 

 

 

프로젝트에 적용하기

 

우선 기존의 코드는 이렇다. 기존에 있던 이력서(findCv)의 값과 새로 요청 받은 이력서 정보(cv)를 비교해서 cv에 새로운 내용이 들어왔으면 findCv를 수정하고, 만약 cv에 해당 필드 값이 존재하지 않으면 findCv도 null로 변경하게 만들었다.

리팩토링 적용 전

 

각각의 필드값들을 하나씩 처리하는 것은 어쩔 수 없었지만, if-else 문이 중복되는 것을 리팩토링해서 단순화하고 중복을 제거하고 싶었다.

 

우선 editField라는 if-else 문의 중복을 처리하는 새로운 메서드를 만들었다.

 

메서드 선언부에서 제네릭 타입 매개변수<T>를 선언해서 Supplier와 consumer가 동일한 타입을 사용하도록 했다. 그리고 cv의 값이 존재하는지 확인하기 위해 supplier.get()을 호출해서 값을 가져온다. 만약 가져온 값이 null인 경우에도 Opional로 감싸서 처리하기 때문에 NPE를 방지할 수 있다.

 

그리고 ifPresentOrElse 메서드를 호출해서 supplier.get()의 결과값이 존재하는 경우에는 consumer를 실행해서 findCv의 필드값을 수정하고 null이 들어오는 경우 consumer.accept(null)로 findCv도 null 값으로 만들어준다.

 

이렇게 editField 메서드를 구현해서 중복된 if-else 문을 간결하게 처리할 수 있었다.

리팩토링 적용 후