ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Java Lazy Evaluation이란?
    Java 2022. 7. 24. 00:01

    Lazy Evaluation이란?

    실제로 필요한 경우에만 연산을 시작하는 것을 의미합니다.

     

    반대로 eager evaluation은 할당되자마자 연산을 시작합니다.

     

    Java는 eager evaluation을 기본으로 하고 일부 Lazy Evaluation이 존재했습니다.

     

    Java8이 나오면서 Java에서 Lazy Evauation을 좀 더 유연하게 사용할 수 있습니다.

     

     

    Eagar Evaluation 예시

    public class LazyEvaluation {
        public static void main(String[] args) throws InterruptedException {
    
            double start = System.currentTimeMillis();
            printIfValid(0,expensiveMethod("junuuu"));
            printIfValid(-1,expensiveMethod("junuuu"));
            printIfValid(-2,expensiveMethod("junuuu"));
    
            System.out.println("소요 시간 : " + (System.currentTimeMillis() - start) / 1000);
    
        }
    
        private static void printIfValid(int validValue, String printValue){
            if(validValue >= 0){
                System.out.println("The value is " + printValue);
            } else{
                System.out.println("Invalid");
            }
    
        }
    
        private static String expensiveMethod(String value) throws InterruptedException {
            Thread.sleep(3000);
            return value;
        }
    }

    위의 코드는 printIfValid 메서드가 3번 호출되고 이에 대한 소요시간을 측정하는 코드입니다.

     

    printIfValid 메서드는 validValue, printValue를 인자로 받고 validValue의 값에 따라 두 번째 인자인 printValue를 사용하기도 하고 사용하지 않기도 합니다.

     

    만약 -1, -2가 첫 번째 인자로 들어왔다면 printValue는 필요하지 않을 것이고 expensiveMethod가 호출되지 않는다면 훨씬 좋을 것입니다.

     

    하지만 위의 결과는 다음과 같이 출력됩니다.

    The value is junuuu
    Invalid
    Invalid
    소요 시간 : 9.019

     

    Java 7 이전의 Lazy Evaluation

    조건문에 직접 명시하는 방법밖에 존재하지 않습니다.

    이렇게 하면 결괏값을 변수로 받은 후 재활용이 안 되는 단점이 있습니다.

     

    예를 들어 printIfValid 메서드가 다음과 같이 변해야 합니다.

    private static void printIfValid(int validValue){
            if(validValue >= 0){
                System.out.println("The value is " + expensiveMethod("junuuu"));
            } else{
                System.out.println("Invalid");
            }
    
        }

     

    이렇게 되면 else 구문에서는 expensiveMethod가 호출되지 않지만 변수로서 재활용도는 떨어지게 됩니다.

     

    Java 8 이후의 Lazy Evaluation

    import java.util.function.Supplier;
    
    public class LazyEvaluation {
        public static void main(String[] args) {
    
            double start = System.currentTimeMillis();
            Supplier<String> printValueSupplier = new Supplier<String>() {
                @Override
                public String get() {
                    return expensiveMethod("junuuu");
                }
            };
    
            printIfValid(0, printValueSupplier);
            printIfValid(-1, () -> expensiveMethod("junuuu"));
            printIfValid(-2, () -> expensiveMethod("kim"));
    
            System.out.println("소요 시간 : " + (System.currentTimeMillis() - start) / 1000);
    
        }
    
        private static void printIfValid(int validValue, Supplier<String> printValueSupplier) {
            if (validValue >= 0) {
                System.out.println("The value is " + printValueSupplier.get());
            } else {
                System.out.println("Invalid");
            }
    
        }
    
        private static String expensiveMethod(String value) {
    
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return value;
        }
    }

     

    다양한 Funtional Interface들이 등장하게 되었고 그중 Supplier라는 함수가 있습니다.

     

    Supplier는 이름을 통해서 유추할 수 있듯이 파라미터를 하나도 받지 않고 T라는 객체를 생성하는 함수입니다.

     

    Supplier는 get 메서드를 통하여 값을 반환할 수 있습니다.

     

    람다식이 익숙하지 않은 분들이 있을 수 있을 것 같아 익명 클래스로 한 번 표현하고 람다식으로 2번 표현해 보았습니다.

     

    원래라면 바로 호출하던 것을 함수화시켜서 실제로 validValue가 0이 넘을 때만 get 메서드를 호출하면서 Lazy Evalutaion이 구현 가능해집니다.

     

    Java 8 Stream과 Lazy Evaluation

    Java 8 Stream에서는 Lazy Evaluation이 기본이 됩니다.

    각 단계에 모든 원소에 대해서 연산을 하지 않고 필요한 부분만 연산을 처리합니다.

     

    만약 List에 1~15까지의 수가 존재하고 여기서 처음 3개의 값을 뽑아내는 연산을 구현해 보겠습니다.

    import java.util.ArrayList;
    import java.util.List;
    
    public class StreamLazyEvaluation {
        public static void main(String[] args) {
            List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
    
            int count = 0;
            List<Integer> result = new ArrayList<>();
            for(Integer cur : numbers){
                System.out.println("curNum : " + cur);
                if(count++ < 3 ){
                    result.add(cur);
                }
            }
            System.out.println(result);
        }
    }

     

    위의 코드로 결과로는 다음과 같이 15번의 curNum이 출력됩니다.

    curNum : 1
    curNum : 2
    curNum : 3
    curNum : 4
    curNum : 5
    curNum : 6
    curNum : 7
    curNum : 8
    curNum : 9
    curNum : 10
    curNum : 11
    curNum : 12
    curNum : 13
    curNum : 14
    curNum : 15
    [1, 2, 3]

     

    즉, Eager Evaluation입니다. 여기서 Stream을 도입해 보겠습니다.

     

    Stream으로 1~15까지에서 처음 3개 수 뽑아내기

    import java.util.List;
    import java.util.stream.Collectors;
    
    public class StreamLazyEvaluation {
        public static void main(String[] args) {
            List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
    
            List<Integer> result = numbers.stream()
                                          .peek(cur -> System.out.println("curNum : " + cur))
                                          .limit(3)
                                          .collect(Collectors.toList());
            System.out.println(result);
        }
    }

    1. List를 stream으로 변환합니다.
    2. 중간중간 현재 수를 peek를 사용하여 출력합니다.

    3. limit메서드로 결과를 최대 3개로 제한합니다.

    4. collect메서드로 결과를 List로 바꿔줍니다.

     

    위의 코드의 결과는 다음과 같습니다.

    curNum : 1
    curNum : 2
    curNum : 3
    [1, 2, 3]

     

    코드도 엄청나게 간결해졌으며, Lazy Evaluation이 적용되었습니다.

     

     

    출처

    https://sabarada.tistory.com/153

     

    [Java] Java와 Lazy Evaluation

    Lazy evaluation은 실제로 필요로 해지는 경우에 연산을 시작하는 것입니다. 이 반대로는 eager evaluation이 있으며 이는 할당되자마다 연산을 시작합니다. 기본적인 Java의 기조는 eager evaluation을 기본으

    sabarada.tistory.com

    https://www.youtube.com/watch?v=7e7FCMFrwcg&list=PLRIMoAKN8c6O8_VHOyBOhzBCeN7ShyJ27&index=7 

    https://sabarada.tistory.com/154?category=815130 

     

    [java] Java와 Lazy evaluation - Java8 Stream

    안녕하세요. 이전시간에 우리는 Lazy evaluation에 대해서 알아보는 시간을 가졌었습니다. 오늘은 이어서 Java8의 Stream의 Lazy Evaluation에 대해서 알아보는 시간을 가져보겠습니다. 우리는 이전 시간 [Ja

    sabarada.tistory.com

     

    댓글

Designed by Tistory.