본문 바로가기
슬기로운 자바 개발자 생활/모던 자바와 Reactive

자바8 람다. 메서드 전달

by 슬기로운 동네 형 2023. 1. 25.
반응형

자바8 람다. 메서드 전달

java 로고

요즘 신규 프로젝트에서 일하게 됐다. 이곳은 자바8을 사용하는 곳.
내 생애 처음 자바8 이상을 사용하는 곳에 왔다.
끄적끄적 도서관에서 자바8과 스프링5 관련 책들을 빌려 람다식, 스트리밍, 리액티브 프로그램 맛보기만 했었다.
개발 시작 전인 분석 및 설계 단계이긴한데 실제 개발이 시작되면 솔직히 람다식이나 스트림 형태로 해도 될지 모르겠다.
프로젝트 관리 파트에서 가이드가 나올텐데...

사용하든 말든 사실 난 관계없다. 뭘로 해도 장단점이 있다고 생각한다.
사용하지 말라하면 하던 데로 하면 되고, 사용해도 된다고 하면 좋은 기회가 되겠지.

이번 포스팅은 오로지 "나"를 위한 포스팅이다.
"모던 자바 인 액션" 한빛미디어에서 출판한 책 속 예제를 올려두고  수시로 확인하며 익숙해지고자 함이다. 도서관에서 3번째 빌려온 책이다. Rx JAVA나 WebFlux 관련 Spring5 책과 함께 보니, 확실히 람다식과 스트림이 익숙해진다.

1. Apple 데이터 객체를 만든다. 무게와 색 정보를 갖고 있다. FilteringApples 클래스 안에 정의했다.

    public static class Apple {
        private int weight = 0;
        private String color = "";

        public Apple(int weight, String color) {
            this.weight = weight;
            this.color = color;
        }

        public int getWeight() {
            return weight;
        }

        public void setWeight(int weight) {
            this.weight = weight;
        }

        public String getColor() {
            return color;
        }

        public void setColor(String color) {
            this.color = color;
        }

        @SuppressWarnings("boxing")
        @Override
        public String toString() {
            return String.format("Apple{color='%s', weight=%d}", color, weight);
        }
    }

2. FilteringApples 안에 FilterGreenApples 메서드를 만든다.
자바 8 이전 방식의 메서드다.
제목 그대로 Apple List 모음을 받아서 Green 사과를 필터링한다.

    public static List<Apple> filterGreenApples(List<Apple> inventory){
        List<Apple> result = new ArrayList<>();
        for(Apple apple:inventory){
            if("green".equals(apple.getColor())){
                result.add(apple);
            }
        }
        return result;
    }

3. FilteringApples 안에 FilterHeavyApples 메서드를 만든다.
자바 8 이전 방식의 메서드다.
제목 그대로 Apple List 모음을 받아서 무게 150 이상의 사과를 필터링한다.

    public static List<Apple> filterHeavyApples(List<Apple> inventory){
        List<Apple> result = new ArrayList<>();
        for(Apple apple:inventory){
            if(apple.getWeight() > 150){
                result.add(apple);
            }
        }
        return result;
    }

4. FilteringApples의

public class FilteringApples {

    public static void main(String[] args) {
		
        // 3개 정도의 사과 리스트를 만든다.
        List<Apple> inventory = Arrays.asList(
                new Apple(80, "green"),
                new Apple(155, "green"),
                new Apple(120, "red")
        );

        // 1. 예전 방식 녹색 사과 필터링
        List<Apple> greenApples = FilteringApples.filterGreenApples(inventory);
        System.out.println(greenApples);

        //2. 150 이상 사과 필터링
        List<Apple> HeavyApples = FilteringApples.filterHeavyApples(inventory);
        System.out.println(HeavyApples);
.....

자바8 이전의 지식을 갖고 있는 개발자들은 위와 같이 필터를 만든다.
실행 모습

자바8 이전의 평범한 코딩으로 실행한 결과

자바8의 람다식 그리고 Predicate를 인자로 받는 함수.
리스트가 아닌 1개의 Apple 객체를 인자로 받아 녹색 사과와 무게 150 이상의 사과를 리턴하는 boolean 펑션이다.
이 두 함수를 자바 8에 새로 생성된 Predicate 펑셔널 함수를 이용해 구현해 본다.

    public static List<Apple> filterApples(List<Apple> inventory,
                                           Predicate<Apple> p){
        List<Apple> result = new ArrayList<>();
        for(Apple apple : inventory){
            if(p.test(apple)){
                result.add(apple);
            }
        }
        return result;
   }
    
   public static boolean isGreenApple(Apple apple){
        return "green".equals(apple.getColor());
    }

    public static boolean isHeavyApple(Apple apple){
        return apple.getWeight() > 150;
    }

FilteringApples의 main 메서드 안에 필터를 적용해 본다.

        List<Apple> greenApples2 = FilteringApples.filterApples(inventory, FilteringApples::isGreenApple);
        System.out.println(greenApples2);

        List<Apple> HeavyApples2 = FilteringApples.filterApples(inventory, FilteringApples::isHeavyApple);
        System.out.println(HeavyApples2);

메서드 레퍼런스는 람다의 축약 표현이다.
다음과 같이 사용할 수 있습니다.
클래스 이름::메서드 이름
생성자::new

메서드를 값으로 전달했다. isHeavyApple, isGreenApple... 비효율적이다. 한두 번 사용하고 만다.
isHeavyApple, isGreenApple 메서드를 정의하거나 만들지 않고 자바 8의 익명 함수(람다) 개념으로 구현할 수 있다.

List<Apple> greenApples3 =FilteringApples.filterApples(inventory,(Apple a)-> a.getColor().equals("green") );
System.out.println(greenApples3);

List<Apple> HeavyApples3 = FilteringApples.filterApples(inventory,(Apple a)-> a.getWeight() > 150);
System.out.println(HeavyApples3);
        
List<Apple> filterApples = FilteringApples.filterApples(inventory, (Apple a) -> a.getWeight() < 80 ||
                                                                                        "red".equals(a.getColor()));
System.out.println(filterApples);

처음 이 코드를 봤을 때... 난해했다. 예제를 8번 정도 보고, 이런저런 예제를 따라 하다 보니 이제야 편해지고 어떻게 사용하는지 감이 온다.
스프링 5의 webFlux, 그리고 리액티브 프로그래밍 방식을 습득하려면 꼭 람다식에 익숙해져야 한다. 물론 Must는 아니지만...

전체 소스코드

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

public class FilteringApples {

    public static void main(String[] args) {
        //System.out.println("================");
        List<Apple> inventory = Arrays.asList(
                new Apple(80, "green"),
                new Apple(155, "green"),
                new Apple(120, "red")
        );

        // 1. 예전 방식 녹색 사과 필터링
        List<Apple> greenApples = FilteringApples.filterGreenApples(inventory);
        System.out.println(greenApples);

        //2. 150 이상 사과 필터링
        List<Apple> HeavyApples = FilteringApples.filterHeavyApples(inventory);
        System.out.println(HeavyApples);


        System.out.println("================================================");
        System.out.println("자바8 방식으로 변경");
        System.out.println("================================================");

        System.out.println("자바8 예제 1");
        List<Apple> greenApples2 = FilteringApples.filterApples(inventory, FilteringApples::isGreenApple);
        System.out.println(greenApples2);

        List<Apple> HeavyApples2 = FilteringApples.filterApples(inventory, FilteringApples::isHeavyApple);
        System.out.println(HeavyApples2);

        System.out.println("자바8 예제 2 축약형");
        List<Apple> greenApples3 =FilteringApples.filterApples(inventory,(Apple a)-> a.getColor().equals("green") );
        System.out.println(greenApples3);

        List<Apple> HeavyApples3 = FilteringApples.filterApples(inventory,(Apple a)-> a.getWeight() > 150);
        System.out.println(HeavyApples3);

        List<Apple> filterApples = FilteringApples.filterApples(inventory, (Apple a) -> a.getWeight() < 80 ||
                                                                                        "red".equals(a.getColor()));
        System.out.println(filterApples);

    }

    public static void myPrint(List<Apple> apples){
        for(Apple apple : apples){
            System.out.println(apple.toString());
        }
    }

    // 1.예전 방식
    public static List<Apple> filterGreenApples(List<Apple> inventory){
        List<Apple> result = new ArrayList<>();
        for(Apple apple:inventory){
            if("green".equals(apple.getColor())){
                result.add(apple);
            }
        }
        return result;
    }

    // 2.예전 방식
    public static List<Apple> filterHeavyApples(List<Apple> inventory){
        List<Apple> result = new ArrayList<>();
        for(Apple apple:inventory){
            if(apple.getWeight() > 150){
                result.add(apple);
            }
        }
        return result;
    }

    // 3. 자바8 방식
    public static boolean isGreenApple(Apple apple){
        return "green".equals(apple.getColor());
    }

    //4. 자바8 방식
    public static boolean isHeavyApple(Apple apple){
        return apple.getWeight() > 150;
    }

    //5. 3과 4를 이용 
    // 메서드가 p라는 이름의 프레디케이트 파라미터로 전달됨
    /*
    참고로
    public interface Predicate<T>{
        boolean test(T t);
    }
     */
    public static List<Apple> filterApples(List<Apple> inventory,
                                           Predicate<Apple> p){
        List<Apple> result = new ArrayList<>();
        for(Apple apple : inventory){
            if(p.test(apple)){
                result.add(apple);
            }
        }
        return result;
    }

    public static class Apple {
        private int weight = 0;
        private String color = "";

        public Apple(int weight, String color) {
            this.weight = weight;
            this.color = color;
        }

        public int getWeight() {
            return weight;
        }

        public void setWeight(int weight) {
            this.weight = weight;
        }

        public String getColor() {
            return color;
        }

        public void setColor(String color) {
            this.color = color;
        }

        @SuppressWarnings("boxing")
        @Override
        public String toString() {
            return String.format("Apple{color='%s', weight=%d}", color, weight);
        }
    }
}
반응형

댓글