[모던 자바 인 액션] Java, 동작의 파라미터화와 람다

안녕하세요. 오늘은 모던자바 인 액션이라는 책을 읽으면서 확인한 동작의 파라미터화라는 키워드에 대해서 이야기해보려고 합니다.

모던 자바 인 액션이라는 책을 간단히 소개하자면 자바 8 이후에 등장하는 드라마틱한 자바 프로그래밍의 패러다임을 정리하여 전달해주고 있습니다. 현업에서 이미 자바8은 너무나도 깊게 자리잡게 되었고 그 원리를 이해하고 그로인해 어플리케이션의 전체적인 성능까지도 고려할 줄 아는 프로그래밍을 위해 자바개발자 독자들에게 그 원리를 전달해주고 있습니다.


http://www.yes24.com/Product/Goods/77125987

 

모던 자바 인 액션

자바 1.0이 나온 이후 18년을 통틀어 가장 큰 변화가 자바 8 이후 이어지고 있다. 자바 8 이후 모던 자바를 이용하면 기존의 자바 코드 모두 그대로 쓸 수 있으며, 새로운 기능과 문법, 디자인 패턴

www.yes24.com

 



동작의 파라미터화라는 말을 처음 들었을때는 너무 개념적으로 와닿지 않았습니다. 자바스크립트를 좀더 알았더라면 아마 쉽게 이해했을텐데.. 최근에 거의 자바만 잡고 있었기때문에..

 

동작 파라미터, 개념적으로 보면 굉장히 역설적인 개념인것 같았습니다. 동작은 뭔가 동적이고 움직이는 그런 다이나믹한 이미지이지만 파라미터는 정적이고 그 자리에 있고 들어오는 값을 받는 그릇 정도로 이해하고 있었습니다. 동적인 개념과 정적인 개념의 조화라고 생각할 수 있겠지만 사실은 동적인 개념의 정적화라고 생각합니다.

 

파라미터라는 정적인 그릇안에 동적인 동작을 담는다. 개발자답게 코드로 보겠습니다.

동작의 파라미터화
    class Apple {
        Integer weight;

        public static List<Apple> toList(Integer... weight) {
            List<Apple> apples = new ArrayList<>(weight.length);
            for (Integer i : weight) {
                apples.add(new Apple(i));
            }
            return apples;
        }
    }

여기 Apple 이라는 클래스가 있습니다. Apple 클래스는 weight라는 무게라는 성질의 변수를 가지고 해당 무게에 따라 특정 동작을 합니다.

예를 들어, 무게가 100 이상인 사과는 상품적 가치가 있기 때문에 상품리스트에 담기고, 무게가 100 미만인 사과는 쓰레기리스트에 담기게 된다고 가정해보겠습니다.

 

무게에 따라 사과를 분류하는 동작
    void 사과분류() {
        List<Apple> apples = Apple.toList(100, 150, 60, 20, 130, 140);
        
        List<Apple> productList = new ArrayList<>();
        List<Apple> trashList = new ArrayList<>();
        
        apples.forEach(apple -> {
            if(apple.getWeight() >= 100) { // 동작은 이곳에서 발생.
                productList.add(apple);
            } else {
                trashList.add(apple);
            }
        });
    }

현재 프로그램의 흐름을 보면 weight를 100과 비교하여 productList와 trashList에 각각 담는 동작을 하고 있다. 자바 8 을 사용하기 전의 일반적인 동작일 것이라고 생각한다. 이 코드가 나쁘다고 할 것도 없고 좋다고 할것도 없지만 그냥저냥 무난한 코드일 것이다.(물론 메소드 제목은 불편하게 보시는 분이 있을지도 모릅니다..)

 

여기서 동작이란 (1) foreach를 돌리는 부분일 수도 있고, (2) apple 인스턴스의 weight값을 비교하여 흐름을 제어하는 부분일 수도 있고, (3) productList, trashList에 apple 인스턴스를 담는 과정일 수도 있습니다.

 

하지만 해당 예제에서는 apple 인스턴스의 weight값을 비교하는 부분을 동작으로 전달해보고 각 동작에 맞는 List를 반환하는 함수를 구현해보겠습니다.

 

Predicate 객체를 이용한 동작 파라미터화 개념의 구현
    List<Apple> filter(List<Apple> apples, Predicate<Apple> applePredicate) {
        return apples.stream()
                     .filter(apple -> applePredicate.test(apple))
                     .collect(Collectors.toList());
    }

 

    void 사과분류() {
        List<Apple> apples = Apple.toList(100, 150, 60, 20, 130, 140);

        // 사과무게 100 이상
        List<Apple> product = filter(apples, apple -> apple.getWeight() >= 100);
        // 사과무게 100 미만
        List<Apple> trash = filter(apples, apple -> apple.getWeight() < 100);
    }

 

filter 메소드의 Predicate 객체를 통해 apple 이라는 인스턴스를 메소드에 전달할 뿐만아니라 apple을 활용한 동작(weight를 가지고 무게 비교)을 파라미터로 전달하여 해당 filter 메소드는 각각 100 이상의 무게와 100 미만의 무게를 비교하여 사과 상품목록과 쓰레기 목록을 가져오게 될 것입니다.

 

결국 저 Lambda 표현[apple -> apple.getWeight() >= 100] 을 통해 동작을 Predicate라는 정적인 객체에 담았고 동작을 담은 정적인 객체를 파라미터로 둠으로써 결국 동작을 파라미터로 받게 되는 것입니다.

 


 

프로그래밍 언어의 문법만을 배우기보다는 개념적 의미를 파악하면서 공부하는 방법의 중요성.

댓글

Designed by JB FACTORY