[Java] 함수를 값으로 넘겨주는 방법 : 인터페이스 선언

정재현·2024년 1월 19일

Java

목록 보기
39/43
post-thumbnail

함수를 매개변수로 넘겨주는 방법 : 함수형 인터페이스 선언

  • 함수를 전달할 때타입을 알려주기 위해함수형 인터페이스를 선언하거나 사용해야 한다.
    • 인터페이스는 타입 역할을 할 수 있기 때문
// 생각해볼 수 있는 함수를 전달하는 방법
public example (매개변수, ... ??? 함수이름) {
	// ??? : 함수의 타입
} 

함수형 인터페이스 특징

  • 추상 메서드를 단 하나만 가지고 있어야 한다
    • 만약 함수형 인터페이스가 추상 메소드가 없거나 두 개 이상의 추상 메서드를 가지고 있다면 함수형 인터페이스라 할 수 없다.

함수형 인터페이스 선언 방법

interface Predicate<T> {
    boolean test(T t);
    // 리턴타입 리팩토링할 메서드
}

함수를 값으로 전달하는 예시 : 인터페이스 선언

  • 인터페이스를 선언해서 내부 주요 로직(두 메서드)을 하나의 함수로 전달받도록 만들기

  • 예시) 리팩토링 전

// Ticket이 있는지 확인하는 메서드
public static List<Car> parkingCarWithTicket(List<Car> carsWantToPark) {
        ArrayList<Car> cars = new ArrayList<>();

        for (Car car : carsWantToPark) {
            if (car.hasParkingTicket()) {
            	// Ticket을 가지고 있을 경우 주차장에 추가
                cars.add(car);
            }
        }

        return cars;
  }

// 티켓머니가 존재하는지 확인하는 메서드
public static List<Car> parkingCarWithMoney(List<Car> carsWantToPark) {
    ArrayList<Car> cars = new ArrayList<>();

    for (Car car : carsWantToPark) {
        if (!car.hasParkingTicket() && car.getParkingMoney() > 1000) {
        	// Ticket은 없지만 머니는 1000원을 초과해서가지고 있을 경우 주차장에 추가
            cars.add(car);
        }
    }

    return cars;
}
  • 예시) 리팩토링 후 ( 함수를 매개변수로 넘기는 방식으로 리팩토링 )
// 변경점 1 : Predicate<Car> 인터페이스를 타입 삼아 함수를 전달
public static List<Car> parkCars(List<Car> carsWantToPark, Predicate<Car> function) {
      List<Car> cars = new ArrayList<>();

      for (Car car : carsWantToPark) {
      	  // 변경점 2 : 전달된 함수 function을 이용해 검증
          if (function.test(car)) {
              cars.add(car);
          }
      }

      return cars;
  }
  • 예시) 리팩토링을 완료한 코드를 추가한 전체 코드 : 주차장 예시
    • 티켓과 파킹머니가 존재해야 주차 가능
import java.util.ArrayList;
import java.util.List;

public class LambdaAndStream {
    public static void main(String[] args) {
    	// 주차 대상 차량
        ArrayList<Car> carsWantToPark = new ArrayList<>();
        // 주차장
        ArrayList<Car> parkingLot = new ArrayList<>();

		// 5개의 Car instance
        Car car1 = new Car("Benz", "Class E", true, 0);
        Car car2 = new Car("BMW", "Series 7", false, 100);
        Car car3 = new Car("BMW", "X9", false, 0);
        Car car4 = new Car("Audi", "A7", true, 0);
        Car car5 = new Car("Hyundai", "Ionic 6", false, 10000);

		// 주차대상 차량에 모두 넣음
        carsWantToPark.add(car1);
        carsWantToPark.add(car2);
        carsWantToPark.add(car3);
        carsWantToPark.add(car4);
        carsWantToPark.add(car5);

		// 모든 차량에 대해서 주차장에 주차 시도 : 2가지 검증
        // hasTicket : Ticket이 존재해야만 주차 가능
        // noTicketButMoney : 주차머니가 존재할 경우 주차 가능
        parkingLot.addAll(parkCars(carsWantToPark, Car::hasTicket));
        parkingLot.addAll(parkCars(carsWantToPark, Car::noTicketButMoney));

		// 주차된 차량 출력
        for (Car car : parkingLot) {
            System.out.println("Parked Car : " + car.getCompany() + "-" + car.getModel());
        }


    }

	// 익명함수로 리팩토링한 코드 : Predicate<Car> function
    public static List<Car> parkCars(List<Car> carsWantToPark, Predicate<Car> function) {
        List<Car> cars = new ArrayList<>();
		
        for (Car car : carsWantToPark) {
        	// 익명함수 사용 코드
            if (function.test(car)) {
                cars.add(car);
            }
        }

        return cars;
    }


}

class Car {
    private final String company; // 자동차 회사
    private final String model; // 자동차 모델

    private final boolean hasParkingTicket;
    private final int parkingMoney;

    public Car(String company, String model, boolean hasParkingTicket, int parkingMoney) {
        this.company = company;
        this.model = model;
        this.hasParkingTicket = hasParkingTicket;
        this.parkingMoney = parkingMoney;
    }

    public String getCompany() {
        return company;
    }

    public String getModel() {
        return model;
    }

    public boolean hasParkingTicket() {
        return hasParkingTicket;
    }

    public int getParkingMoney() {
        return parkingMoney;
    }

    public static boolean hasTicket(Car car) {
        return car.hasParkingTicket;
    }

    public static boolean noTicketButMoney(Car car) {
        return !car.hasParkingTicket && car.getParkingMoney() > 1000;
    }
}

interface Predicate<T> {
    boolean test(T t);
}
  • 실제로 사용하는 방법
    • 함수를 값으로 취급하기 때문에 함수를 참조로 불러서 사용 가능
    • ex. Car 클래스의 hasTicket 함수를 값으로 가져와서 전달하는 코드
    • ex. Car 클래스 안에 있는 어떤 함수를 호출한다 해서 Car::~~~로 사용
parkingLot.addAll(parkCars(carsWantToPark, Car::hasTicket));
parkingLot.addAll(parkCars(carsWantToPark, Car::noTicketButMoney));

profile
공부 기록 보관소

0개의 댓글