Method References

푸드테크·2022년 10월 26일
0

Car class

public class Car {
    
    private Long idx;

    private String name;

    private String brand;

    public Car(final Long idx) {
        this.idx = idx;
    }

    public Car() {
    }

    public boolean isHyundai() {
        return this.brand.equals("Hyundai");
    }

    public void nameSout() {
        System.out.println(this.name);
    }

    public Long getIdx() {
        return idx;
    }

    public String getName() {
        return name;
    }

    public String getBrand() {
        return brand;
    }
}

Function

final Function<Long, Car> carCreate1 = Car::new;
final Function<Long, Car> carCreate2 = (x) -> new Car(x);

List.of(1l).stream().map(carCreate1).collect(Collectors.toList());
List.of(1l).stream().map(carCreate2).collect(Collectors.toList());

Function은 하나의 인자값을 받아 1개의 객체를 리턴하는 함수형 인터페이스 이다.

위의 Car::new; 는 Car의 idx를 받는 생성자를 참조한다.

Supplier

final Supplier<Car> carCreate3 = Car::new;
final Supplier<Car> carCreate4 = () -> new Car();

List.of(new Car()).stream().map(car -> carCreate3).collect(Collectors.toList());
List.of(new Car()).stream().map(car -> carCreate4).collect(Collectors.toList());

Supplier는 인자값을 받지 않고 객체를 리턴하는 함수형 인터페이스 이다.

위의 코드는 조금 어거지로 만들었으니 참조 정도로만 생각하길 바란다.

위의 Car::new; 는 위와 다르게 기본 생성자를 참조한다.

Consumer

final Consumer<Car> nameSout1 = Car::nameSout;
final Consumer<Car> nameSout2 = car -> System.out.println("hi");

List.of(new Car()).stream().peek(nameSout1).collect(Collectors.toList());
List.of(new Car()).stream().peek(nameSout2).collect(Collectors.toList());

Consumer 는 1개의 인자값을 받아 아무것도 리턴하지 않는 함수형 인터페이스 이다.

Predicate

final Predicate<Car> isHyundai1 = Car::isHyundai;
final Predicate<Car> isHyundai2 = car -> car.getBrand().equals("Hyundai");

List.of(new Car()).stream().filter(isHyundai1).collect(Collectors.toList());
List.of(new Car()).stream().filter(isHyundai2).collect(Collectors.toList());

Predicate는 1개의 인자값을 받아 Boolean을 반환하는 함수형 인터페이스이다.

결론

이상 기본적인 자바에서 알아야할 기본적이 4가지 함수형 인터페이스를 나열하고 기능을 정리했다.

그리고 이 글의 중요 포인트는 따로 있다.

보면 두가지 방법으로 선언했는데 위의 선언 방법

final Predicate isHyundai1 = Car::isHyundai; 은 객체 내부의 클레스를 사용하는 방법이다.

아래의 선언 방법

final Predicate isHyundai2 = car -> car.getBrand().equals("Hyundai");은 Car 객체와 상관없이 익명 메소드를 정리하였다.

이게 뭐? 라고 생각하실수도 있겠지만

이 두가지의 방법을 정확히 이해했다면 위는 객체지향적 코딩이고 아래는 함수형 코딩으로 전혀 설계 방법이 달라진다는걸 알수 있다.

아래의 방법으로 코딩할 경우 Car 객체의 내부 메소드는 없어지고 데이터만이 남고 기능은 아예 분리되어 있어 OCP를 지키기 좋다.

기능을 아무리 수정해도 Car 객체를 참조하고 있는 모든곳에는 영향도가 없다.

반면 위의 코딩 방법으로 할 경우 Car 객체의 내부 메소드만을 이용하기 때문에 데이터 + 기능이 되어 있어 캡슐화를 잘 지킬수 있다.

장담점은 객체지향 코딩과 함수형 코딩 그대로 생각하면 된다. 어떤 설계를 하든 잃는것과 얻는것이 있고 이것을 잘 저울질 해야된다.

profile
푸드 테크 기술 블로그

1개의 댓글

comment-user-thumbnail
2022년 10월 26일

너무 좋은글입니다. Stream 람다에서 허용되는 범위에 대해 공부해 볼수있는 글이네요!

답글 달기